@timmy6942025/cli-timer 1.1.4 → 1.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +4 -0
  2. package/package.json +1 -1
  3. package/src/index.js +106 -29
package/README.md CHANGED
@@ -116,3 +116,7 @@ Controls in settings UI:
116
116
  - `Esc`/`q`: back/cancel
117
117
 
118
118
  Note for macOS: If system notifications are inconsistent with built-in AppleScript notifications, install `terminal-notifier` (`brew install terminal-notifier`) for improved reliability.
119
+
120
+ Notification notes by platform:
121
+ - Windows: notifications depend on OS notification permissions and whether your desktop session allows toasts/balloons.
122
+ - Linux: notifications require a running desktop notification daemon (`notify-send` talks to that daemon over D-Bus).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@timmy6942025/cli-timer",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Simple customizable terminal timer and stopwatch",
5
5
  "main": "src/index.js",
6
6
  "bin": {
package/src/index.js CHANGED
@@ -497,6 +497,56 @@ function sleepSync(ms) {
497
497
  }
498
498
  }
499
499
 
500
+ function readProcessCommand(pid) {
501
+ try {
502
+ const result = spawnSync("ps", ["-p", String(pid), "-o", "comm="], { encoding: "utf8", stdio: "pipe" });
503
+ if (result.error || result.status !== 0) {
504
+ return "";
505
+ }
506
+ return String(result.stdout || "").trim();
507
+ } catch (_error) {
508
+ return "";
509
+ }
510
+ }
511
+
512
+ function resolveMacNotificationSenderCandidates() {
513
+ const candidates = [];
514
+ const explicit = String(process.env.CLI_TIMER_NOTIFICATION_SENDER || "").trim();
515
+ if (explicit) {
516
+ candidates.push(explicit);
517
+ }
518
+
519
+ const termProgram = String(process.env.TERM_PROGRAM || "").toLowerCase();
520
+ if (termProgram === "apple_terminal") {
521
+ candidates.push("com.apple.Terminal");
522
+ } else if (termProgram === "iterm.app") {
523
+ candidates.push("com.googlecode.iterm2");
524
+ } else if (termProgram === "vscode") {
525
+ candidates.push("com.microsoft.VSCode");
526
+ } else if (termProgram === "warpterminal" || termProgram === "warp") {
527
+ candidates.push("dev.warp.Warp-Stable");
528
+ }
529
+
530
+ const parentCommand = readProcessCommand(process.ppid).toLowerCase();
531
+ if (parentCommand.includes("terminal.app")) {
532
+ candidates.push("com.apple.Terminal");
533
+ }
534
+ if (parentCommand.includes("iterm")) {
535
+ candidates.push("com.googlecode.iterm2");
536
+ }
537
+ if (parentCommand.includes("warp")) {
538
+ candidates.push("dev.warp.Warp-Stable");
539
+ }
540
+ if (parentCommand.includes("visual studio code") || parentCommand.includes("vscode")) {
541
+ candidates.push("com.microsoft.VSCode");
542
+ }
543
+ if (parentCommand.includes("codex.app")) {
544
+ candidates.push("com.openai.codex");
545
+ }
546
+
547
+ return [...new Set(candidates)].filter(Boolean);
548
+ }
549
+
500
550
  function terminalNotifierDelivered(groupId) {
501
551
  try {
502
552
  for (let attempt = 0; attempt < MAC_NOTIFICATION_VERIFY_ATTEMPTS; attempt += 1) {
@@ -514,8 +564,6 @@ function terminalNotifierDelivered(groupId) {
514
564
  return false;
515
565
  } catch (_error) {
516
566
  return false;
517
- } finally {
518
- spawnOk("terminal-notifier", ["-remove", groupId]);
519
567
  }
520
568
  }
521
569
 
@@ -529,12 +577,27 @@ function sendSystemNotification({ title, message }) {
529
577
 
530
578
  try {
531
579
  if (process.platform === "darwin") {
532
- const groupId = `cli-timer-${Date.now()}-${Math.floor(Math.random() * 1e9)}`;
533
- if (
534
- spawnOk("terminal-notifier", ["-title", safeTitle, "-message", safeMessage, "-group", groupId, "-ignoreDnD"])
535
- ) {
536
- if (terminalNotifierDelivered(groupId)) {
537
- return true;
580
+ const senderCandidates = resolveMacNotificationSenderCandidates();
581
+ const senderArgsSets = senderCandidates.map((bundleId) => ["-sender", bundleId]);
582
+ senderArgsSets.push([]);
583
+
584
+ for (const senderArgs of senderArgsSets) {
585
+ const groupId = `cli-timer-${Date.now()}-${Math.floor(Math.random() * 1e9)}`;
586
+ if (
587
+ spawnOk("terminal-notifier", [
588
+ "-title",
589
+ safeTitle,
590
+ "-message",
591
+ safeMessage,
592
+ "-group",
593
+ groupId,
594
+ "-ignoreDnD",
595
+ ...senderArgs
596
+ ])
597
+ ) {
598
+ if (terminalNotifierDelivered(groupId)) {
599
+ return true;
600
+ }
538
601
  }
539
602
  }
540
603
  const script = `display notification "${escapeAppleScriptString(safeMessage)}" with title "${escapeAppleScriptString(safeTitle)}"`;
@@ -548,26 +611,6 @@ function sendSystemNotification({ title, message }) {
548
611
  const titlePs = escapePowerShellSingleQuotedString(safeTitle);
549
612
  const messagePs = escapePowerShellSingleQuotedString(safeMessage);
550
613
 
551
- const ps = [
552
- "$ErrorActionPreference = 'Stop'",
553
- "try {",
554
- " [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null",
555
- " $template = [Windows.UI.Notifications.ToastTemplateType]::ToastText02",
556
- " $xml = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($template)",
557
- " $txt = $xml.GetElementsByTagName('text')",
558
- ` $txt.Item(0).AppendChild($xml.CreateTextNode('${titlePs}')) > $null`,
559
- ` $txt.Item(1).AppendChild($xml.CreateTextNode('${messagePs}')) > $null`,
560
- " $toast = [Windows.UI.Notifications.ToastNotification]::new($xml)",
561
- " $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('cli-timer')",
562
- " $notifier.Show($toast)",
563
- "} catch { exit 1 }"
564
- ].join("; ");
565
-
566
- const powershellArgs = ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Sta", "-Command", ps];
567
- if (spawnOk("powershell", powershellArgs, { windowsHide: true })) {
568
- return true;
569
- }
570
-
571
614
  const balloon = [
572
615
  "$ErrorActionPreference = 'Stop'",
573
616
  "try {",
@@ -593,13 +636,47 @@ function sendSystemNotification({ title, message }) {
593
636
  "-Command",
594
637
  balloon
595
638
  ];
596
- return spawnOk("powershell", balloonArgs, { windowsHide: true });
639
+ if (spawnOk("powershell", balloonArgs, { windowsHide: true })) {
640
+ return true;
641
+ }
642
+
643
+ const ps = [
644
+ "$ErrorActionPreference = 'Stop'",
645
+ "try {",
646
+ " [Windows.UI.Notifications.ToastNotificationManager, Windows.UI.Notifications, ContentType = WindowsRuntime] > $null",
647
+ " $template = [Windows.UI.Notifications.ToastTemplateType]::ToastText02",
648
+ " $xml = [Windows.UI.Notifications.ToastNotificationManager]::GetTemplateContent($template)",
649
+ " $txt = $xml.GetElementsByTagName('text')",
650
+ ` $txt.Item(0).AppendChild($xml.CreateTextNode('${titlePs}')) > $null`,
651
+ ` $txt.Item(1).AppendChild($xml.CreateTextNode('${messagePs}')) > $null`,
652
+ " $toast = [Windows.UI.Notifications.ToastNotification]::new($xml)",
653
+ " $notifier = [Windows.UI.Notifications.ToastNotificationManager]::CreateToastNotifier('cli-timer')",
654
+ " $notifier.Show($toast)",
655
+ "} catch { exit 1 }"
656
+ ].join("; ");
657
+
658
+ const powershellArgs = ["-NoProfile", "-NonInteractive", "-ExecutionPolicy", "Bypass", "-Sta", "-Command", ps];
659
+ if (spawnOk("powershell", powershellArgs, { windowsHide: true })) {
660
+ return true;
661
+ }
662
+ return false;
597
663
  }
598
664
 
599
665
  if (process.platform === "linux") {
600
666
  if (spawnOk("termux-notification", ["--title", safeTitle, "--content", safeMessage])) {
601
667
  return true;
602
668
  }
669
+ if (
670
+ spawnOk("notify-send", [
671
+ "--app-name=cli-timer",
672
+ "--urgency=critical",
673
+ "--icon=dialog-information",
674
+ safeTitle,
675
+ safeMessage
676
+ ])
677
+ ) {
678
+ return true;
679
+ }
603
680
  if (spawnOk("notify-send", [safeTitle, safeMessage])) {
604
681
  return true;
605
682
  }