@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/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@qodalis/cli-stopwatch",
|
|
3
|
+
"version": "2.0.0-beta.1",
|
|
4
|
+
"description": "Interactive stopwatch and countdown timer",
|
|
5
|
+
"author": "Qodalis Solutions",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/qodalis-solutions/web-cli"
|
|
10
|
+
},
|
|
11
|
+
"homepage": "https://qodalis.com",
|
|
12
|
+
"keywords": [
|
|
13
|
+
"cli",
|
|
14
|
+
"qodalis",
|
|
15
|
+
"terminal",
|
|
16
|
+
"stopwatch"
|
|
17
|
+
],
|
|
18
|
+
"umd": "./umd/index.js",
|
|
19
|
+
"unpkg": "./umd/index.js",
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@qodalis/cli-core": "2.0.0-beta.1"
|
|
22
|
+
},
|
|
23
|
+
"sideEffects": false,
|
|
24
|
+
"main": "./public-api.js",
|
|
25
|
+
"module": "./public-api.mjs",
|
|
26
|
+
"types": "./public-api.d.ts",
|
|
27
|
+
"exports": {
|
|
28
|
+
".": {
|
|
29
|
+
"types": "./public-api.d.ts",
|
|
30
|
+
"import": "./public-api.mjs",
|
|
31
|
+
"require": "./public-api.js"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
package/public-api.d.mts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as _qodalis_cli_core from '@qodalis/cli-core';
|
|
2
|
+
import { ICliCommandProcessor, CliProcessCommand, ICliExecutionContext, ICliModule } from '@qodalis/cli-core';
|
|
3
|
+
|
|
4
|
+
declare class CliStopwatchCommandProcessor implements ICliCommandProcessor {
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
aliases: string[];
|
|
8
|
+
author: _qodalis_cli_core.ICliCommandAuthor;
|
|
9
|
+
version: string;
|
|
10
|
+
processors: ICliCommandProcessor[];
|
|
11
|
+
private startTime;
|
|
12
|
+
private elapsed;
|
|
13
|
+
private running;
|
|
14
|
+
private laps;
|
|
15
|
+
private intervalId;
|
|
16
|
+
private context;
|
|
17
|
+
processCommand(_command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
|
|
18
|
+
onData(data: string, context: ICliExecutionContext): Promise<void>;
|
|
19
|
+
onResize(_cols: number, _rows: number, context: ICliExecutionContext): void;
|
|
20
|
+
onDispose(_context: ICliExecutionContext): void;
|
|
21
|
+
writeDescription(context: ICliExecutionContext): void;
|
|
22
|
+
private reset;
|
|
23
|
+
private resetAndRestart;
|
|
24
|
+
private togglePause;
|
|
25
|
+
private recordLap;
|
|
26
|
+
private exit;
|
|
27
|
+
private startTicking;
|
|
28
|
+
private clearInterval;
|
|
29
|
+
private currentElapsed;
|
|
30
|
+
private render;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parse duration string: 30s, 5m, 1h, 2h30m, etc.
|
|
35
|
+
* Returns null for invalid or too-short durations.
|
|
36
|
+
*/
|
|
37
|
+
declare function parseDuration(input: string): number | null;
|
|
38
|
+
/**
|
|
39
|
+
* Format milliseconds as HH:MM:SS.mmm
|
|
40
|
+
*/
|
|
41
|
+
declare function formatDuration(ms: number): string;
|
|
42
|
+
|
|
43
|
+
declare const LIBRARY_VERSION = "2.0.0-beta.1";
|
|
44
|
+
declare const API_VERSION = 2;
|
|
45
|
+
|
|
46
|
+
declare const stopwatchModule: ICliModule;
|
|
47
|
+
|
|
48
|
+
export { API_VERSION, CliStopwatchCommandProcessor, LIBRARY_VERSION, formatDuration, parseDuration, stopwatchModule };
|
package/public-api.d.ts
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import * as _qodalis_cli_core from '@qodalis/cli-core';
|
|
2
|
+
import { ICliCommandProcessor, CliProcessCommand, ICliExecutionContext, ICliModule } from '@qodalis/cli-core';
|
|
3
|
+
|
|
4
|
+
declare class CliStopwatchCommandProcessor implements ICliCommandProcessor {
|
|
5
|
+
command: string;
|
|
6
|
+
description: string;
|
|
7
|
+
aliases: string[];
|
|
8
|
+
author: _qodalis_cli_core.ICliCommandAuthor;
|
|
9
|
+
version: string;
|
|
10
|
+
processors: ICliCommandProcessor[];
|
|
11
|
+
private startTime;
|
|
12
|
+
private elapsed;
|
|
13
|
+
private running;
|
|
14
|
+
private laps;
|
|
15
|
+
private intervalId;
|
|
16
|
+
private context;
|
|
17
|
+
processCommand(_command: CliProcessCommand, context: ICliExecutionContext): Promise<void>;
|
|
18
|
+
onData(data: string, context: ICliExecutionContext): Promise<void>;
|
|
19
|
+
onResize(_cols: number, _rows: number, context: ICliExecutionContext): void;
|
|
20
|
+
onDispose(_context: ICliExecutionContext): void;
|
|
21
|
+
writeDescription(context: ICliExecutionContext): void;
|
|
22
|
+
private reset;
|
|
23
|
+
private resetAndRestart;
|
|
24
|
+
private togglePause;
|
|
25
|
+
private recordLap;
|
|
26
|
+
private exit;
|
|
27
|
+
private startTicking;
|
|
28
|
+
private clearInterval;
|
|
29
|
+
private currentElapsed;
|
|
30
|
+
private render;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Parse duration string: 30s, 5m, 1h, 2h30m, etc.
|
|
35
|
+
* Returns null for invalid or too-short durations.
|
|
36
|
+
*/
|
|
37
|
+
declare function parseDuration(input: string): number | null;
|
|
38
|
+
/**
|
|
39
|
+
* Format milliseconds as HH:MM:SS.mmm
|
|
40
|
+
*/
|
|
41
|
+
declare function formatDuration(ms: number): string;
|
|
42
|
+
|
|
43
|
+
declare const LIBRARY_VERSION = "2.0.0-beta.1";
|
|
44
|
+
declare const API_VERSION = 2;
|
|
45
|
+
|
|
46
|
+
declare const stopwatchModule: ICliModule;
|
|
47
|
+
|
|
48
|
+
export { API_VERSION, CliStopwatchCommandProcessor, LIBRARY_VERSION, formatDuration, parseDuration, stopwatchModule };
|
package/public-api.js
ADDED
|
@@ -0,0 +1,418 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var cliCore = require('@qodalis/cli-core');
|
|
4
|
+
|
|
5
|
+
// src/lib/processors/cli-stopwatch-command-processor.ts
|
|
6
|
+
|
|
7
|
+
// src/lib/version.ts
|
|
8
|
+
var LIBRARY_VERSION = "2.0.0-beta.1";
|
|
9
|
+
var API_VERSION = 2;
|
|
10
|
+
|
|
11
|
+
// src/lib/stopwatch-utils.ts
|
|
12
|
+
var MIN_INTERVAL_MS = 1e4;
|
|
13
|
+
function parseDuration(input) {
|
|
14
|
+
if (!input.trim()) return null;
|
|
15
|
+
if (/^\d+$/.test(input.trim())) {
|
|
16
|
+
const ms = parseInt(input.trim(), 10) * 1e3;
|
|
17
|
+
return ms >= MIN_INTERVAL_MS ? ms : null;
|
|
18
|
+
}
|
|
19
|
+
const pattern = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s)?$/;
|
|
20
|
+
const match = input.trim().match(pattern);
|
|
21
|
+
if (!match || !match[0] || match[0] === "") return null;
|
|
22
|
+
const h = parseInt(match[1] ?? "0", 10);
|
|
23
|
+
const m = parseInt(match[2] ?? "0", 10);
|
|
24
|
+
const s = parseInt(match[3] ?? "0", 10);
|
|
25
|
+
const total = h * 36e5 + m * 6e4 + s * 1e3;
|
|
26
|
+
return total >= MIN_INTERVAL_MS ? total : null;
|
|
27
|
+
}
|
|
28
|
+
function formatDuration(ms) {
|
|
29
|
+
const h = Math.floor(ms / 36e5);
|
|
30
|
+
const m = Math.floor(ms % 36e5 / 6e4);
|
|
31
|
+
const s = Math.floor(ms % 6e4 / 1e3);
|
|
32
|
+
const millis = ms % 1e3;
|
|
33
|
+
return [
|
|
34
|
+
String(h).padStart(2, "0"),
|
|
35
|
+
String(m).padStart(2, "0"),
|
|
36
|
+
String(s).padStart(2, "0")
|
|
37
|
+
].join(":") + "." + String(millis).padStart(3, "0");
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// src/lib/processors/cli-stopwatch-command-processor.ts
|
|
41
|
+
var ESC = "\x1B";
|
|
42
|
+
var CSI = `${ESC}[`;
|
|
43
|
+
var ansi = {
|
|
44
|
+
clearScreen: `${CSI}2J`,
|
|
45
|
+
cursorHome: `${CSI}H`,
|
|
46
|
+
hideCursor: `${CSI}?25l`,
|
|
47
|
+
showCursor: `${CSI}?25h`,
|
|
48
|
+
cursorTo: (row, col) => `${CSI}${row};${col}H`,
|
|
49
|
+
bold: `${CSI}1m`,
|
|
50
|
+
dim: `${CSI}2m`,
|
|
51
|
+
reset: `${CSI}0m`,
|
|
52
|
+
fg: {
|
|
53
|
+
white: `${CSI}97m`,
|
|
54
|
+
cyan: `${CSI}36m`,
|
|
55
|
+
yellow: `${CSI}93m`,
|
|
56
|
+
green: `${CSI}32m`,
|
|
57
|
+
red: `${CSI}91m`,
|
|
58
|
+
gray: `${CSI}90m`,
|
|
59
|
+
brightGreen: `${CSI}92m`,
|
|
60
|
+
brightCyan: `${CSI}96m`
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
var CliStopwatchTimerCommandProcessor = class {
|
|
64
|
+
constructor() {
|
|
65
|
+
this.command = "timer";
|
|
66
|
+
this.description = "Run a countdown timer (e.g. timer 5m, timer 1h30m, timer 90s)";
|
|
67
|
+
this.author = cliCore.DefaultLibraryAuthor;
|
|
68
|
+
this.version = LIBRARY_VERSION;
|
|
69
|
+
this.acceptsRawInput = true;
|
|
70
|
+
this.intervalId = null;
|
|
71
|
+
this.remaining = 0;
|
|
72
|
+
this.total = 0;
|
|
73
|
+
this.running = false;
|
|
74
|
+
this.done = false;
|
|
75
|
+
this.context = null;
|
|
76
|
+
}
|
|
77
|
+
async processCommand(command, context) {
|
|
78
|
+
const input = (command.value ?? "").trim();
|
|
79
|
+
const durationMs = parseDuration(input);
|
|
80
|
+
if (!durationMs) {
|
|
81
|
+
context.writer.writeError(
|
|
82
|
+
input ? `Invalid or too-short duration "${input}". Use formats like 30s, 5m, 1h, 2h30m (minimum 10s).` : "Usage: stopwatch timer <duration> (e.g. timer 5m)"
|
|
83
|
+
);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
this.total = durationMs;
|
|
87
|
+
this.remaining = durationMs;
|
|
88
|
+
this.running = true;
|
|
89
|
+
this.done = false;
|
|
90
|
+
this.context = context;
|
|
91
|
+
context.enterFullScreenMode(this);
|
|
92
|
+
this.render(context);
|
|
93
|
+
this.intervalId = setInterval(() => {
|
|
94
|
+
if (!this.running) return;
|
|
95
|
+
this.remaining = Math.max(0, this.remaining - 100);
|
|
96
|
+
this.render(context);
|
|
97
|
+
if (this.remaining === 0) {
|
|
98
|
+
this.finishTimer(context);
|
|
99
|
+
}
|
|
100
|
+
}, 100);
|
|
101
|
+
}
|
|
102
|
+
async onData(data, context) {
|
|
103
|
+
if (this.done) {
|
|
104
|
+
this.exit(context);
|
|
105
|
+
return;
|
|
106
|
+
}
|
|
107
|
+
switch (data) {
|
|
108
|
+
case " ":
|
|
109
|
+
case "p":
|
|
110
|
+
case "P":
|
|
111
|
+
this.running = !this.running;
|
|
112
|
+
this.render(context);
|
|
113
|
+
break;
|
|
114
|
+
case "r":
|
|
115
|
+
case "R":
|
|
116
|
+
this.remaining = this.total;
|
|
117
|
+
this.running = false;
|
|
118
|
+
this.render(context);
|
|
119
|
+
break;
|
|
120
|
+
// L=lap not applicable to countdown timer
|
|
121
|
+
case "q":
|
|
122
|
+
case "Q":
|
|
123
|
+
case "":
|
|
124
|
+
this.exit(context);
|
|
125
|
+
break;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
onDispose(_context) {
|
|
129
|
+
this.clearInterval();
|
|
130
|
+
}
|
|
131
|
+
onResize(_cols, _rows, context) {
|
|
132
|
+
this.render(context);
|
|
133
|
+
}
|
|
134
|
+
finishTimer(context) {
|
|
135
|
+
this.clearInterval();
|
|
136
|
+
this.running = false;
|
|
137
|
+
this.done = true;
|
|
138
|
+
this.renderDone(context);
|
|
139
|
+
}
|
|
140
|
+
exit(context) {
|
|
141
|
+
this.clearInterval();
|
|
142
|
+
this.running = false;
|
|
143
|
+
context.exitFullScreenMode();
|
|
144
|
+
if (this.done) {
|
|
145
|
+
context.writer.writeSuccess("Timer complete!");
|
|
146
|
+
} else {
|
|
147
|
+
const elapsed = this.total - this.remaining;
|
|
148
|
+
context.writer.writeln(
|
|
149
|
+
`Timer stopped. Elapsed: ${formatDuration(elapsed)} / ${formatDuration(this.total)}`
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
this.context = null;
|
|
153
|
+
}
|
|
154
|
+
clearInterval() {
|
|
155
|
+
if (this.intervalId !== null) {
|
|
156
|
+
clearInterval(this.intervalId);
|
|
157
|
+
this.intervalId = null;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
render(context) {
|
|
161
|
+
const cols = context.terminal.cols;
|
|
162
|
+
const rows = context.terminal.rows;
|
|
163
|
+
const centerRow = Math.floor(rows / 2);
|
|
164
|
+
const buf = [];
|
|
165
|
+
buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);
|
|
166
|
+
const title = " COUNTDOWN TIMER ";
|
|
167
|
+
const titleCol = Math.max(1, Math.floor((cols - title.length) / 2) + 1);
|
|
168
|
+
buf.push(ansi.cursorTo(centerRow - 4, titleCol));
|
|
169
|
+
buf.push(ansi.fg.cyan, ansi.bold, title, ansi.reset);
|
|
170
|
+
const timeStr = formatDuration(this.remaining);
|
|
171
|
+
const timeCol = Math.max(1, Math.floor((cols - timeStr.length) / 2) + 1);
|
|
172
|
+
buf.push(ansi.cursorTo(centerRow - 2, timeCol));
|
|
173
|
+
buf.push(ansi.bold, ansi.fg.yellow, timeStr, ansi.reset);
|
|
174
|
+
const barWidth = Math.min(50, cols - 6);
|
|
175
|
+
const fraction = this.total > 0 ? (this.total - this.remaining) / this.total : 0;
|
|
176
|
+
const filled = Math.round(fraction * barWidth);
|
|
177
|
+
const empty = barWidth - filled;
|
|
178
|
+
const barCol = Math.max(1, Math.floor((cols - barWidth - 2) / 2) + 1);
|
|
179
|
+
buf.push(ansi.cursorTo(centerRow, barCol));
|
|
180
|
+
buf.push(ansi.fg.gray, "[", ansi.reset);
|
|
181
|
+
if (filled > 0) {
|
|
182
|
+
buf.push(ansi.fg.brightGreen, "=".repeat(filled), ansi.reset);
|
|
183
|
+
}
|
|
184
|
+
if (empty > 0) {
|
|
185
|
+
buf.push(ansi.fg.gray, " ".repeat(empty), ansi.reset);
|
|
186
|
+
}
|
|
187
|
+
buf.push(ansi.fg.gray, "]", ansi.reset);
|
|
188
|
+
const pct = Math.round(fraction * 100);
|
|
189
|
+
const pctStr = `${pct}%`;
|
|
190
|
+
const pctCol = Math.max(1, Math.floor((cols - pctStr.length) / 2) + 1);
|
|
191
|
+
buf.push(ansi.cursorTo(centerRow + 1, pctCol));
|
|
192
|
+
buf.push(ansi.fg.gray, pctStr, ansi.reset);
|
|
193
|
+
buf.push(ansi.cursorTo(centerRow + 2, Math.max(1, Math.floor((cols - 8) / 2) + 1)));
|
|
194
|
+
if (!this.running) {
|
|
195
|
+
buf.push(ansi.fg.yellow, " PAUSED ", ansi.reset);
|
|
196
|
+
} else {
|
|
197
|
+
buf.push(" ");
|
|
198
|
+
}
|
|
199
|
+
const hint = "[Space/P] Pause [R] Reset [Q] Quit";
|
|
200
|
+
const hintCol = Math.max(1, Math.floor((cols - hint.length) / 2) + 1);
|
|
201
|
+
buf.push(ansi.cursorTo(centerRow + 4, hintCol));
|
|
202
|
+
buf.push(ansi.dim, hint, ansi.reset);
|
|
203
|
+
context.terminal.write(buf.join(""));
|
|
204
|
+
}
|
|
205
|
+
renderDone(context) {
|
|
206
|
+
const cols = context.terminal.cols;
|
|
207
|
+
const rows = context.terminal.rows;
|
|
208
|
+
const centerRow = Math.floor(rows / 2);
|
|
209
|
+
const buf = [];
|
|
210
|
+
buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);
|
|
211
|
+
const msg1 = "Timer complete!";
|
|
212
|
+
const msg2 = formatDuration(this.total);
|
|
213
|
+
const msg3 = "Press any key to exit";
|
|
214
|
+
buf.push(ansi.cursorTo(centerRow - 2, Math.max(1, Math.floor((cols - msg1.length) / 2) + 1)));
|
|
215
|
+
buf.push(ansi.fg.brightGreen, ansi.bold, msg1, ansi.reset);
|
|
216
|
+
buf.push(ansi.cursorTo(centerRow, Math.max(1, Math.floor((cols - msg2.length) / 2) + 1)));
|
|
217
|
+
buf.push(ansi.fg.cyan, msg2, ansi.reset);
|
|
218
|
+
buf.push(ansi.cursorTo(centerRow + 2, Math.max(1, Math.floor((cols - msg3.length) / 2) + 1)));
|
|
219
|
+
buf.push(ansi.dim, msg3, ansi.reset);
|
|
220
|
+
context.terminal.write(buf.join(""));
|
|
221
|
+
}
|
|
222
|
+
};
|
|
223
|
+
var CliStopwatchCommandProcessor = class {
|
|
224
|
+
constructor() {
|
|
225
|
+
this.command = "stopwatch";
|
|
226
|
+
this.description = "Interactive stopwatch and countdown timer";
|
|
227
|
+
this.aliases = ["sw"];
|
|
228
|
+
this.author = cliCore.DefaultLibraryAuthor;
|
|
229
|
+
this.version = LIBRARY_VERSION;
|
|
230
|
+
this.processors = [
|
|
231
|
+
new CliStopwatchTimerCommandProcessor()
|
|
232
|
+
];
|
|
233
|
+
// Stopwatch state
|
|
234
|
+
this.startTime = 0;
|
|
235
|
+
this.elapsed = 0;
|
|
236
|
+
this.running = false;
|
|
237
|
+
this.laps = [];
|
|
238
|
+
this.intervalId = null;
|
|
239
|
+
this.context = null;
|
|
240
|
+
}
|
|
241
|
+
async processCommand(_command, context) {
|
|
242
|
+
this.reset();
|
|
243
|
+
this.context = context;
|
|
244
|
+
context.enterFullScreenMode(this);
|
|
245
|
+
this.startTicking(context);
|
|
246
|
+
this.render(context);
|
|
247
|
+
}
|
|
248
|
+
async onData(data, context) {
|
|
249
|
+
switch (data) {
|
|
250
|
+
case " ":
|
|
251
|
+
case "p":
|
|
252
|
+
case "P":
|
|
253
|
+
this.togglePause(context);
|
|
254
|
+
break;
|
|
255
|
+
case "l":
|
|
256
|
+
case "L":
|
|
257
|
+
this.recordLap(context);
|
|
258
|
+
break;
|
|
259
|
+
case "r":
|
|
260
|
+
case "R":
|
|
261
|
+
this.resetAndRestart(context);
|
|
262
|
+
break;
|
|
263
|
+
case "q":
|
|
264
|
+
case "Q":
|
|
265
|
+
case "":
|
|
266
|
+
this.exit(context);
|
|
267
|
+
break;
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
onResize(_cols, _rows, context) {
|
|
271
|
+
this.render(context);
|
|
272
|
+
}
|
|
273
|
+
onDispose(_context) {
|
|
274
|
+
this.clearInterval();
|
|
275
|
+
}
|
|
276
|
+
writeDescription(context) {
|
|
277
|
+
const { writer } = context;
|
|
278
|
+
writer.writeln(this.description);
|
|
279
|
+
writer.writeln();
|
|
280
|
+
writer.writeln("Usage:");
|
|
281
|
+
writer.writeln(" stopwatch Start interactive stopwatch");
|
|
282
|
+
writer.writeln(" stopwatch timer <duration> Run countdown timer");
|
|
283
|
+
writer.writeln();
|
|
284
|
+
writer.writeln("Duration formats: 30s, 5m, 1h, 2h30m, 1h30m45s");
|
|
285
|
+
writer.writeln();
|
|
286
|
+
writer.writeln("Stopwatch controls:");
|
|
287
|
+
writer.writeln(" [Space/P] Pause / resume");
|
|
288
|
+
writer.writeln(" [L] Record lap");
|
|
289
|
+
writer.writeln(" [R] Reset");
|
|
290
|
+
writer.writeln(" [Q/Ctrl+C] Quit");
|
|
291
|
+
}
|
|
292
|
+
// -- Internal helpers ---------------------------------------------------
|
|
293
|
+
reset() {
|
|
294
|
+
this.clearInterval();
|
|
295
|
+
this.startTime = Date.now();
|
|
296
|
+
this.elapsed = 0;
|
|
297
|
+
this.running = true;
|
|
298
|
+
this.laps = [];
|
|
299
|
+
}
|
|
300
|
+
resetAndRestart(context) {
|
|
301
|
+
this.reset();
|
|
302
|
+
this.startTicking(context);
|
|
303
|
+
this.render(context);
|
|
304
|
+
}
|
|
305
|
+
togglePause(context) {
|
|
306
|
+
if (this.running) {
|
|
307
|
+
this.elapsed += Date.now() - this.startTime;
|
|
308
|
+
this.running = false;
|
|
309
|
+
this.clearInterval();
|
|
310
|
+
} else {
|
|
311
|
+
this.startTime = Date.now();
|
|
312
|
+
this.running = true;
|
|
313
|
+
this.startTicking(context);
|
|
314
|
+
}
|
|
315
|
+
this.render(context);
|
|
316
|
+
}
|
|
317
|
+
recordLap(context) {
|
|
318
|
+
const current = this.currentElapsed();
|
|
319
|
+
this.laps.push(current);
|
|
320
|
+
this.render(context);
|
|
321
|
+
}
|
|
322
|
+
exit(context) {
|
|
323
|
+
this.clearInterval();
|
|
324
|
+
const finalTime = this.currentElapsed();
|
|
325
|
+
context.exitFullScreenMode();
|
|
326
|
+
context.writer.writeln(`Final time: ${formatDuration(finalTime)}`);
|
|
327
|
+
if (this.laps.length > 0) {
|
|
328
|
+
context.writer.writeln("Laps:");
|
|
329
|
+
this.laps.forEach((lap, i) => {
|
|
330
|
+
context.writer.writeln(` Lap ${i + 1}: ${formatDuration(lap)}`);
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
this.context = null;
|
|
334
|
+
}
|
|
335
|
+
startTicking(context) {
|
|
336
|
+
this.clearInterval();
|
|
337
|
+
this.intervalId = setInterval(() => {
|
|
338
|
+
this.render(context);
|
|
339
|
+
}, 100);
|
|
340
|
+
}
|
|
341
|
+
clearInterval() {
|
|
342
|
+
if (this.intervalId !== null) {
|
|
343
|
+
clearInterval(this.intervalId);
|
|
344
|
+
this.intervalId = null;
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
currentElapsed() {
|
|
348
|
+
if (this.running) {
|
|
349
|
+
return this.elapsed + (Date.now() - this.startTime);
|
|
350
|
+
}
|
|
351
|
+
return this.elapsed;
|
|
352
|
+
}
|
|
353
|
+
// -- Rendering ----------------------------------------------------------
|
|
354
|
+
render(context) {
|
|
355
|
+
const cols = context.terminal.cols;
|
|
356
|
+
const rows = context.terminal.rows;
|
|
357
|
+
const centerRow = Math.floor(rows / 2);
|
|
358
|
+
const buf = [];
|
|
359
|
+
buf.push(ansi.clearScreen, ansi.cursorHome, ansi.hideCursor);
|
|
360
|
+
const title = " STOPWATCH ";
|
|
361
|
+
const titleCol = Math.max(1, Math.floor((cols - title.length) / 2) + 1);
|
|
362
|
+
buf.push(ansi.cursorTo(centerRow - 4, titleCol));
|
|
363
|
+
buf.push(ansi.fg.cyan, ansi.bold, title, ansi.reset);
|
|
364
|
+
const timeStr = formatDuration(this.currentElapsed());
|
|
365
|
+
const timeCol = Math.max(1, Math.floor((cols - timeStr.length) / 2) + 1);
|
|
366
|
+
buf.push(ansi.cursorTo(centerRow - 2, timeCol));
|
|
367
|
+
buf.push(ansi.bold, ansi.fg.yellow, timeStr, ansi.reset);
|
|
368
|
+
const statusStr = this.running ? " RUNNING " : " PAUSED ";
|
|
369
|
+
const statusColor = this.running ? ansi.fg.brightGreen : ansi.fg.yellow;
|
|
370
|
+
const statusCol = Math.max(1, Math.floor((cols - statusStr.length) / 2) + 1);
|
|
371
|
+
buf.push(ansi.cursorTo(centerRow, statusCol));
|
|
372
|
+
buf.push(statusColor, statusStr, ansi.reset);
|
|
373
|
+
const hint = "[Space/P] Pause [L] Lap [R] Reset [Q/Ctrl+C] Quit";
|
|
374
|
+
const hintCol = Math.max(1, Math.floor((cols - hint.length) / 2) + 1);
|
|
375
|
+
buf.push(ansi.cursorTo(centerRow + 2, hintCol));
|
|
376
|
+
buf.push(ansi.dim, hint, ansi.reset);
|
|
377
|
+
if (this.laps.length > 0) {
|
|
378
|
+
const lapsToShow = this.laps.slice(-5);
|
|
379
|
+
const startIndex = this.laps.length - lapsToShow.length;
|
|
380
|
+
lapsToShow.forEach((lap, i) => {
|
|
381
|
+
const lapIndex = startIndex + i + 1;
|
|
382
|
+
const lapStr = `Lap ${lapIndex}: ${formatDuration(lap)}`;
|
|
383
|
+
const lapCol = Math.max(1, Math.floor((cols - lapStr.length) / 2) + 1);
|
|
384
|
+
buf.push(ansi.cursorTo(centerRow + 4 + i, lapCol));
|
|
385
|
+
buf.push(ansi.fg.gray, lapStr, ansi.reset);
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
context.terminal.write(buf.join(""));
|
|
389
|
+
}
|
|
390
|
+
};
|
|
391
|
+
|
|
392
|
+
// src/public-api.ts
|
|
393
|
+
var stopwatchModule = {
|
|
394
|
+
apiVersion: API_VERSION,
|
|
395
|
+
name: "@qodalis/cli-stopwatch",
|
|
396
|
+
processors: [new CliStopwatchCommandProcessor()],
|
|
397
|
+
translations: {
|
|
398
|
+
es: { "cli.stopwatch.description": "Cron\xF3metro interactivo y temporizador" },
|
|
399
|
+
fr: { "cli.stopwatch.description": "Chronom\xE8tre interactif et minuteur" },
|
|
400
|
+
de: { "cli.stopwatch.description": "Interaktive Stoppuhr und Countdown-Timer" },
|
|
401
|
+
pt: { "cli.stopwatch.description": "Cron\xF4metro interativo e temporizador" },
|
|
402
|
+
it: { "cli.stopwatch.description": "Cronometro interattivo e timer" },
|
|
403
|
+
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" },
|
|
404
|
+
ko: { "cli.stopwatch.description": "\uB300\uD654\uD615 \uC2A4\uD1B1\uC6CC\uCE58 \uBC0F \uD0C0\uC774\uBA38" },
|
|
405
|
+
zh: { "cli.stopwatch.description": "\u4EA4\u4E92\u5F0F\u79D2\u8868\u548C\u5012\u8BA1\u65F6\u5668" },
|
|
406
|
+
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" },
|
|
407
|
+
ro: { "cli.stopwatch.description": "Cronometru interactiv \u0219i num\u0103r\u0103toare invers\u0103" }
|
|
408
|
+
}
|
|
409
|
+
};
|
|
410
|
+
|
|
411
|
+
exports.API_VERSION = API_VERSION;
|
|
412
|
+
exports.CliStopwatchCommandProcessor = CliStopwatchCommandProcessor;
|
|
413
|
+
exports.LIBRARY_VERSION = LIBRARY_VERSION;
|
|
414
|
+
exports.formatDuration = formatDuration;
|
|
415
|
+
exports.parseDuration = parseDuration;
|
|
416
|
+
exports.stopwatchModule = stopwatchModule;
|
|
417
|
+
//# sourceMappingURL=public-api.js.map
|
|
418
|
+
//# sourceMappingURL=public-api.js.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":["DefaultLibraryAuthor"],"mappings":"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","file":"public-api.js","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"]}
|