pomotty 1.2.0 → 1.2.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.
- package/README.ja.md +1 -1
- package/README.md +1 -1
- package/dist/cli.js +28 -45
- package/package.json +12 -9
package/README.ja.md
CHANGED
package/README.md
CHANGED
package/dist/cli.js
CHANGED
|
@@ -7,7 +7,7 @@ import path from "node:path";
|
|
|
7
7
|
import { setTimeout as setTimeout$1 } from "node:timers/promises";
|
|
8
8
|
import { on } from "node:events";
|
|
9
9
|
import { emitKeypressEvents } from "node:readline";
|
|
10
|
-
|
|
10
|
+
// src/diagnostics/writer.ts
|
|
11
11
|
/**
|
|
12
12
|
* 診断の出力先が閉じていても失敗しない書き込み処理を生成します。
|
|
13
13
|
*
|
|
@@ -33,8 +33,7 @@ const createDiagnosticWriter = (stream = process$1.stderr) => {
|
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
35
|
};
|
|
36
|
-
|
|
37
|
-
//#region src/notification/operation.ts
|
|
36
|
+
// src/notification/operation.ts
|
|
38
37
|
const SUCCESS_EXIT_CODE$1 = 0;
|
|
39
38
|
const EMPTY_SIZE = 0;
|
|
40
39
|
const PLAYER_TIMEOUT_MS = 1e4;
|
|
@@ -235,8 +234,7 @@ const createOperationTracker = (spawnChild = spawnNodeChild) => {
|
|
|
235
234
|
}
|
|
236
235
|
};
|
|
237
236
|
};
|
|
238
|
-
|
|
239
|
-
//#region src/notification/sound.ts
|
|
237
|
+
// src/notification/sound.ts
|
|
240
238
|
const FALLBACK_SOUNDS = {
|
|
241
239
|
break: "\x07\x07",
|
|
242
240
|
work: "\x07"
|
|
@@ -285,8 +283,7 @@ const createSoundPlayer = ({ commands, environment = process$1.env, soundDirecto
|
|
|
285
283
|
},
|
|
286
284
|
shutdown: (options) => tracker.shutdown(options)
|
|
287
285
|
});
|
|
288
|
-
|
|
289
|
-
//#region src/diagnostics/escape.ts
|
|
286
|
+
// src/diagnostics/escape.ts
|
|
290
287
|
const BACKSLASH = "\\";
|
|
291
288
|
const BIDIRECTIONAL_PATTERN = /[\u061C\u200B\u200E\u200F\u2028-\u202E\u2066-\u206F\uFEFF]/u;
|
|
292
289
|
const CONTROL_HEX_LENGTH = 2;
|
|
@@ -318,8 +315,7 @@ const escapeDiagnostic = (value) => {
|
|
|
318
315
|
if (codePoints.length > MAXIMUM_CODE_POINTS) return `${QUOTATION_MARK}${escaped}${TRUNCATION_MARK}${QUOTATION_MARK}`;
|
|
319
316
|
return `${QUOTATION_MARK}${escaped}${QUOTATION_MARK}`;
|
|
320
317
|
};
|
|
321
|
-
|
|
322
|
-
//#region src/platform/commands.ts
|
|
318
|
+
// src/platform/commands.ts
|
|
323
319
|
const AFPLAY_PATH = "/usr/bin/afplay";
|
|
324
320
|
const DEFAULT_LINUX_PATH = [
|
|
325
321
|
"/usr/local/bin",
|
|
@@ -429,8 +425,7 @@ const resolvePlayerCommands = ({ cwd = process$1.cwd(), environment = process$1.
|
|
|
429
425
|
default: return {};
|
|
430
426
|
}
|
|
431
427
|
};
|
|
432
|
-
|
|
433
|
-
//#region src/timer/state.ts
|
|
428
|
+
// src/timer/state.ts
|
|
434
429
|
const FIRST_CYCLE$1 = 1;
|
|
435
430
|
const COUNT_INCREMENT = 1;
|
|
436
431
|
const NO_TIME$1 = 0;
|
|
@@ -604,8 +599,7 @@ const runPomodoroTimer = async ({ workDurationMs = DEFAULT_WORK_DURATION_MS, bre
|
|
|
604
599
|
onTick?.(state, currentTime);
|
|
605
600
|
}
|
|
606
601
|
};
|
|
607
|
-
|
|
608
|
-
//#region src/terminal/output.ts
|
|
602
|
+
// src/terminal/output.ts
|
|
609
603
|
/** 出力先が閉じたパイプであることを示すエラーコードです。 */
|
|
610
604
|
const BROKEN_PIPE_CODE = "EPIPE";
|
|
611
605
|
const isBrokenPipe = (error) => typeof error === "object" && error !== null && Reflect.get(error, "code") === BROKEN_PIPE_CODE;
|
|
@@ -648,15 +642,14 @@ const OPTIONS = [
|
|
|
648
642
|
name: "--help"
|
|
649
643
|
}
|
|
650
644
|
];
|
|
651
|
-
|
|
652
|
-
//#region src/terminal/input.ts
|
|
645
|
+
// src/terminal/input.ts
|
|
653
646
|
const CHOICES = ["OK", "NG"];
|
|
654
647
|
const ENTER_KEY_NAMES = /* @__PURE__ */ new Set(["enter", "return"]);
|
|
655
648
|
const FIRST_CHOICE_INDEX = 0;
|
|
656
649
|
const KEYPRESS_EVENT_KEY_INDEX = 1;
|
|
657
650
|
const MOVE_KEY_NAMES = /* @__PURE__ */ new Set(["down", "up"]);
|
|
658
651
|
const NEXT_INDEX_OFFSET = 1;
|
|
659
|
-
const
|
|
652
|
+
const CLEAR_SELECTION_SEQUENCE = `\r\u001B[${CHOICES.length}A\u001B[J`;
|
|
660
653
|
const STDIN_CLOSE_EVENTS = ["end", "close"];
|
|
661
654
|
const SELECTION_QUESTION = "Start working? (Use ↑/↓ to select, Enter to confirm)";
|
|
662
655
|
const keyFrom = (value) => {
|
|
@@ -717,12 +710,16 @@ const handleKey = (key, selectedIndex, terminal) => {
|
|
|
717
710
|
}
|
|
718
711
|
if (MOVE_KEY_NAMES.has(key.name)) {
|
|
719
712
|
const newSelectedIndex = nextChoiceIndex(selectedIndex);
|
|
720
|
-
terminal.write(`${
|
|
713
|
+
terminal.write(`${CLEAR_SELECTION_SEQUENCE}${renderSelection(newSelectedIndex)}`);
|
|
721
714
|
return newSelectedIndex;
|
|
722
715
|
}
|
|
723
716
|
if (ENTER_KEY_NAMES.has(key.name)) {
|
|
717
|
+
if (CHOICES[selectedIndex] === "OK") {
|
|
718
|
+
terminal.write(CLEAR_SELECTION_SEQUENCE);
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
724
721
|
terminal.write("\n");
|
|
725
|
-
return
|
|
722
|
+
return false;
|
|
726
723
|
}
|
|
727
724
|
return selectedIndex;
|
|
728
725
|
};
|
|
@@ -740,8 +737,7 @@ const confirmWorkStart = async ({ createTerminal = createSelectionTerminal, ...t
|
|
|
740
737
|
await terminal.restore();
|
|
741
738
|
}
|
|
742
739
|
};
|
|
743
|
-
|
|
744
|
-
//#region src/terminal/constants.ts
|
|
740
|
+
// src/terminal/constants.ts
|
|
745
741
|
/**
|
|
746
742
|
* ロゴが収まらない狭い端末で、ロゴの代わりに表示する見出しです。
|
|
747
743
|
*/
|
|
@@ -756,8 +752,7 @@ const LOGO = `
|
|
|
756
752
|
██║ ╚██████╔╝██║ ╚═╝ ██║╚██████╔╝ ██║ ██║ ██║
|
|
757
753
|
╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═════╝ ╚═╝ ╚═╝ ╚═╝
|
|
758
754
|
`;
|
|
759
|
-
|
|
760
|
-
//#region src/terminal/frame-line.ts
|
|
755
|
+
// src/terminal/frame-line.ts
|
|
761
756
|
const ELLIPSIS = "…";
|
|
762
757
|
const NO_WIDTH = 0;
|
|
763
758
|
const SINGLE_WIDTH = 1;
|
|
@@ -813,8 +808,7 @@ const stringifySegment = ({ text, tone }, color) => {
|
|
|
813
808
|
};
|
|
814
809
|
const stringifyFrameLine = (line, color) => line.map((segment) => stringifySegment(segment, color)).join("").trimEnd();
|
|
815
810
|
const isColorEnabled = (env) => (env.NO_COLOR ?? "") === "";
|
|
816
|
-
|
|
817
|
-
//#region src/terminal/render.ts
|
|
811
|
+
// src/terminal/render.ts
|
|
818
812
|
const CLI_OPTION_INDEX = 2;
|
|
819
813
|
const LOGO_WIDTH = Math.max(...LOGO.split("\n").map((line) => cellWidth(line)));
|
|
820
814
|
const RIGHT_MARGIN$1 = 1;
|
|
@@ -835,8 +829,7 @@ const createCliOutput = ({ columns, options, optionName = process.argv.at(CLI_OP
|
|
|
835
829
|
""
|
|
836
830
|
].join("\n");
|
|
837
831
|
};
|
|
838
|
-
|
|
839
|
-
//#region src/terminal/inline-renderer.ts
|
|
832
|
+
// src/terminal/inline-renderer.ts
|
|
840
833
|
const CSI = "\x1B[";
|
|
841
834
|
const NO_ROWS = 0;
|
|
842
835
|
const CLEAR_LINE = `${CSI}2K`;
|
|
@@ -872,8 +865,7 @@ const createInlineRenderer = (write) => {
|
|
|
872
865
|
}
|
|
873
866
|
};
|
|
874
867
|
};
|
|
875
|
-
|
|
876
|
-
//#region src/terminal/terminal-guard.ts
|
|
868
|
+
// src/terminal/terminal-guard.ts
|
|
877
869
|
const HIDE_CURSOR = "\x1B[?25l";
|
|
878
870
|
const SHOW_CURSOR = "\x1B[?25h";
|
|
879
871
|
const TERMINATION_SIGNALS = [
|
|
@@ -914,8 +906,7 @@ const createTerminalGuard = ({ onSignal, processEvents, terminal, write }) => {
|
|
|
914
906
|
}
|
|
915
907
|
};
|
|
916
908
|
};
|
|
917
|
-
|
|
918
|
-
//#region src/terminal/clock.ts
|
|
909
|
+
// src/terminal/clock.ts
|
|
919
910
|
const MILLISECONDS_PER_SECOND = 1e3;
|
|
920
911
|
const SECONDS_PER_MINUTE = 60;
|
|
921
912
|
const SECONDS_PER_HOUR = 3600;
|
|
@@ -946,8 +937,7 @@ const progressFor = (state, now, settings) => {
|
|
|
946
937
|
totalSeconds
|
|
947
938
|
};
|
|
948
939
|
};
|
|
949
|
-
|
|
950
|
-
//#region src/terminal/timeline.ts
|
|
940
|
+
// src/terminal/timeline.ts
|
|
951
941
|
const BLOCK = "█";
|
|
952
942
|
const EMPTY_CELL = "·";
|
|
953
943
|
const EIGHTH_BLOCKS = [
|
|
@@ -1046,8 +1036,7 @@ const createTimeline = (state, settings, ratio) => {
|
|
|
1046
1036
|
[{ text: `${prefix}${createLegend(settings, cells)}` }]
|
|
1047
1037
|
];
|
|
1048
1038
|
};
|
|
1049
|
-
|
|
1050
|
-
//#region src/terminal/timer-view.ts
|
|
1039
|
+
// src/terminal/timer-view.ts
|
|
1051
1040
|
const BAR_WIDTH = 40;
|
|
1052
1041
|
const INDENT = " ";
|
|
1053
1042
|
const MIN_GAP = 2;
|
|
@@ -1253,8 +1242,7 @@ const createTimerFrame = ({ state, now, settings, columns }) => {
|
|
|
1253
1242
|
if (width >= COMPACT_MIN_WIDTH) return createCompactFrame(layout).map((line) => truncateLine(line, width));
|
|
1254
1243
|
return createMinimalFrame(layout).map((line) => truncateLine(line, width));
|
|
1255
1244
|
};
|
|
1256
|
-
|
|
1257
|
-
//#region src/terminal/timer-keys.ts
|
|
1245
|
+
// src/terminal/timer-keys.ts
|
|
1258
1246
|
/** Ctrlなしで受け付けるキー名と操作の対応です。Shift(大文字)は区別しません。 */
|
|
1259
1247
|
const PLAIN_KEYS = /* @__PURE__ */ new Map([
|
|
1260
1248
|
["q", "quit"],
|
|
@@ -1288,8 +1276,7 @@ const watchTimerKeys = ({ input = process$1.stdin, onKey }) => {
|
|
|
1288
1276
|
if (!inputWasFlowing) input.pause();
|
|
1289
1277
|
};
|
|
1290
1278
|
};
|
|
1291
|
-
|
|
1292
|
-
//#region src/cli/progress-view.ts
|
|
1279
|
+
// src/cli/progress-view.ts
|
|
1293
1280
|
const PHASE_ICONS = {
|
|
1294
1281
|
break: "☕",
|
|
1295
1282
|
work: "🍅"
|
|
@@ -1389,8 +1376,7 @@ const createProgressView = ({ color = isColorEnabled(process$1.env), interactive
|
|
|
1389
1376
|
write
|
|
1390
1377
|
});
|
|
1391
1378
|
};
|
|
1392
|
-
|
|
1393
|
-
//#region src/cli/parse-arguments.ts
|
|
1379
|
+
// src/cli/parse-arguments.ts
|
|
1394
1380
|
const ARGUMENT_INDEX_INCREMENT = 1;
|
|
1395
1381
|
const ARGUMENTS_START_INDEX = 0;
|
|
1396
1382
|
const DURATION_PATTERN = /^[1-9][0-9]{0,3}$/u;
|
|
@@ -1464,8 +1450,7 @@ const parseCliArguments = (arguments_) => {
|
|
|
1464
1450
|
workDurationMinutes
|
|
1465
1451
|
};
|
|
1466
1452
|
};
|
|
1467
|
-
|
|
1468
|
-
//#region src/cli/run.ts
|
|
1453
|
+
// src/cli/run.ts
|
|
1469
1454
|
const CLI_ARGUMENTS_START_INDEX = 2;
|
|
1470
1455
|
const FAILURE_EXIT_CODE$1 = 1;
|
|
1471
1456
|
const SUCCESS_EXIT_CODE = 0;
|
|
@@ -1593,8 +1578,7 @@ const runCli = async ({ arguments_ = process$1.argv.slice(CLI_ARGUMENTS_START_IN
|
|
|
1593
1578
|
throw error;
|
|
1594
1579
|
}
|
|
1595
1580
|
};
|
|
1596
|
-
|
|
1597
|
-
//#region src/cli.ts
|
|
1581
|
+
// src/cli.ts
|
|
1598
1582
|
const FAILURE_EXIT_CODE = 1;
|
|
1599
1583
|
const SOUND_DIRECTORY = new URL("../assets/", import.meta.url);
|
|
1600
1584
|
const UNCONVERTIBLE_VALUE_MESSAGE = "Unable to convert the thrown value to a string";
|
|
@@ -1617,5 +1601,4 @@ try {
|
|
|
1617
1601
|
} catch (error) {
|
|
1618
1602
|
handleFailure(error);
|
|
1619
1603
|
}
|
|
1620
|
-
//#endregion
|
|
1621
1604
|
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pomotty",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.2",
|
|
4
4
|
"description": "An interactive terminal Pomodoro timer with configurable work and break sessions and sound notifications.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"cli",
|
|
@@ -34,12 +34,13 @@
|
|
|
34
34
|
"registry": "https://registry.npmjs.org/"
|
|
35
35
|
},
|
|
36
36
|
"devDependencies": {
|
|
37
|
-
"@types/node": "22.20.
|
|
38
|
-
"
|
|
39
|
-
"
|
|
40
|
-
"
|
|
37
|
+
"@types/node": "22.20.5",
|
|
38
|
+
"@vitest/coverage-v8": "^4.1.12",
|
|
39
|
+
"oxfmt": "^0.75.0",
|
|
40
|
+
"oxlint": "^1.90.0",
|
|
41
|
+
"tsdown": "^0.23.4",
|
|
41
42
|
"typescript": "^7.0.2",
|
|
42
|
-
"vitest": "^4.1.
|
|
43
|
+
"vitest": "^4.1.12"
|
|
43
44
|
},
|
|
44
45
|
"devEngines": {
|
|
45
46
|
"packageManager": {
|
|
@@ -48,17 +49,19 @@
|
|
|
48
49
|
}
|
|
49
50
|
},
|
|
50
51
|
"engines": {
|
|
51
|
-
"node": "
|
|
52
|
+
"node": ">=22.18.0"
|
|
52
53
|
},
|
|
53
54
|
"scripts": {
|
|
54
55
|
"build": "tsdown",
|
|
55
|
-
"typecheck": "tsc -p tsconfig.json",
|
|
56
56
|
"check": "pnpm typecheck && pnpm build && pnpm test",
|
|
57
57
|
"start": "pnpm build && node dist/cli.js",
|
|
58
|
+
"typecheck": "tsc --noEmit",
|
|
58
59
|
"lint": "oxlint . --deny-warnings --report-unused-disable-directives-severity=error",
|
|
59
60
|
"lint:fix": "oxlint . --fix --deny-warnings --report-unused-disable-directives-severity=error",
|
|
60
61
|
"format": "oxfmt --write",
|
|
61
62
|
"format:check": "oxfmt --check",
|
|
62
|
-
"test": "vitest run --dir src"
|
|
63
|
+
"test": "vitest run --dir src",
|
|
64
|
+
"test:coverage": "vitest run --dir src --coverage",
|
|
65
|
+
"test:watch": "vitest --dir src"
|
|
63
66
|
}
|
|
64
67
|
}
|