@timmy6942025/cli-timer 1.1.16 → 1.1.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +10 -0
- package/package.json +1 -1
- package/src/index.js +149 -0
package/README.md
CHANGED
|
@@ -45,6 +45,16 @@ timer 5 min 2 sec
|
|
|
45
45
|
|
|
46
46
|
By default, timer and stopwatch output is centered in the terminal.
|
|
47
47
|
|
|
48
|
+
### Update CLI Timer
|
|
49
|
+
|
|
50
|
+
To update globally and verify you are on latest:
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
timer update
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
`timer update` auto-detects whether your current install came from Bun, npm, or pnpm, runs the matching global update command, then checks your installed version against npm `latest`.
|
|
57
|
+
|
|
48
58
|
## Controls
|
|
49
59
|
|
|
50
60
|
- `p` or `Spacebar`: Pause/Resume
|
package/package.json
CHANGED
package/src/index.js
CHANGED
|
@@ -12,6 +12,7 @@ const SETTINGS_STATE_PATH = path.join(CONFIG_DIR, "settings-state.json");
|
|
|
12
12
|
const DEFAULT_FONT = "Standard";
|
|
13
13
|
const TIMER_SAMPLE_TEXT = "01:23:45";
|
|
14
14
|
const MIN_FIGLET_WIDTH = 120;
|
|
15
|
+
const PACKAGE_NAME = "@timmy6942025/cli-timer";
|
|
15
16
|
const PRINTABLE_ASCII_CANDIDATES = Object.freeze(
|
|
16
17
|
Array.from({ length: 94 }, (_, index) => String.fromCharCode(33 + index))
|
|
17
18
|
);
|
|
@@ -696,6 +697,147 @@ function spawnOk(command, args, options) {
|
|
|
696
697
|
}
|
|
697
698
|
}
|
|
698
699
|
|
|
700
|
+
function readCurrentPackageVersion() {
|
|
701
|
+
try {
|
|
702
|
+
const packagePath = path.join(PROJECT_ROOT, "package.json");
|
|
703
|
+
const text = fs.readFileSync(packagePath, "utf8");
|
|
704
|
+
const parsed = JSON.parse(text);
|
|
705
|
+
if (!parsed || typeof parsed.version !== "string") {
|
|
706
|
+
return null;
|
|
707
|
+
}
|
|
708
|
+
return parsed.version.trim() || null;
|
|
709
|
+
} catch (_error) {
|
|
710
|
+
return null;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
|
|
714
|
+
function readLatestPublishedVersion() {
|
|
715
|
+
try {
|
|
716
|
+
const result = spawnSync("npm", ["view", PACKAGE_NAME, "version", "--registry=https://registry.npmjs.org"], {
|
|
717
|
+
encoding: "utf8",
|
|
718
|
+
stdio: ["ignore", "pipe", "pipe"]
|
|
719
|
+
});
|
|
720
|
+
if (result.error || result.status !== 0) {
|
|
721
|
+
return null;
|
|
722
|
+
}
|
|
723
|
+
const version = String(result.stdout || "").trim();
|
|
724
|
+
return version || null;
|
|
725
|
+
} catch (_error) {
|
|
726
|
+
return null;
|
|
727
|
+
}
|
|
728
|
+
}
|
|
729
|
+
|
|
730
|
+
function detectInstallMethod() {
|
|
731
|
+
try {
|
|
732
|
+
const realRoot = fs.realpathSync(PROJECT_ROOT).replace(/\\/g, "/").toLowerCase();
|
|
733
|
+
if (realRoot.includes("/.bun/install/global/node_modules/")) {
|
|
734
|
+
return "bun";
|
|
735
|
+
}
|
|
736
|
+
if (
|
|
737
|
+
realRoot.includes("/.local/share/pnpm/global/") ||
|
|
738
|
+
realRoot.includes("/pnpm/global/") ||
|
|
739
|
+
realRoot.includes("/.pnpm/")
|
|
740
|
+
) {
|
|
741
|
+
return "pnpm";
|
|
742
|
+
}
|
|
743
|
+
if (realRoot.includes("/node_modules/")) {
|
|
744
|
+
return "npm";
|
|
745
|
+
}
|
|
746
|
+
} catch (_error) {
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
const userAgent = String(process.env.npm_config_user_agent || "").toLowerCase();
|
|
750
|
+
if (userAgent.startsWith("bun/")) {
|
|
751
|
+
return "bun";
|
|
752
|
+
}
|
|
753
|
+
if (userAgent.startsWith("pnpm/")) {
|
|
754
|
+
return "pnpm";
|
|
755
|
+
}
|
|
756
|
+
if (userAgent.startsWith("npm/")) {
|
|
757
|
+
return "npm";
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
return "npm";
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
function getUpdateCommand(method) {
|
|
764
|
+
const packageTarget = `${PACKAGE_NAME}@latest`;
|
|
765
|
+
if (method === "bun") {
|
|
766
|
+
return {
|
|
767
|
+
command: "bun",
|
|
768
|
+
args: ["add", "-g", packageTarget],
|
|
769
|
+
printable: `bun add -g ${packageTarget}`
|
|
770
|
+
};
|
|
771
|
+
}
|
|
772
|
+
if (method === "pnpm") {
|
|
773
|
+
return {
|
|
774
|
+
command: "pnpm",
|
|
775
|
+
args: ["add", "-g", packageTarget],
|
|
776
|
+
printable: `pnpm add -g ${packageTarget}`
|
|
777
|
+
};
|
|
778
|
+
}
|
|
779
|
+
return {
|
|
780
|
+
command: "npm",
|
|
781
|
+
args: ["i", "-g", packageTarget],
|
|
782
|
+
printable: `npm i -g ${packageTarget}`
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
function runSelfUpdate() {
|
|
787
|
+
const method = detectInstallMethod();
|
|
788
|
+
const updateCommand = getUpdateCommand(method);
|
|
789
|
+
const beforeVersion = readCurrentPackageVersion();
|
|
790
|
+
const latestVersion = readLatestPublishedVersion();
|
|
791
|
+
|
|
792
|
+
process.stdout.write(`Detected install method: ${method}\n`);
|
|
793
|
+
if (beforeVersion) {
|
|
794
|
+
process.stdout.write(`Current version: ${beforeVersion}\n`);
|
|
795
|
+
}
|
|
796
|
+
if (latestVersion) {
|
|
797
|
+
process.stdout.write(`Latest version: ${latestVersion}\n`);
|
|
798
|
+
}
|
|
799
|
+
process.stdout.write(`Running: ${updateCommand.printable}\n\n`);
|
|
800
|
+
|
|
801
|
+
let result;
|
|
802
|
+
try {
|
|
803
|
+
result = spawnSync(updateCommand.command, updateCommand.args, { stdio: "inherit" });
|
|
804
|
+
} catch (error) {
|
|
805
|
+
process.stderr.write(`Failed to run updater: ${error.message}\n`);
|
|
806
|
+
process.exitCode = 1;
|
|
807
|
+
return;
|
|
808
|
+
}
|
|
809
|
+
|
|
810
|
+
if (result.error || result.status !== 0) {
|
|
811
|
+
process.stderr.write(`Update command failed: ${updateCommand.printable}\n`);
|
|
812
|
+
process.exitCode = 1;
|
|
813
|
+
return;
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
const installedAfter = readCurrentPackageVersion();
|
|
817
|
+
const latestAfter = readLatestPublishedVersion();
|
|
818
|
+
|
|
819
|
+
process.stdout.write("\nUpdate finished.\n");
|
|
820
|
+
if (installedAfter) {
|
|
821
|
+
process.stdout.write(`Installed version: ${installedAfter}\n`);
|
|
822
|
+
}
|
|
823
|
+
if (latestAfter) {
|
|
824
|
+
process.stdout.write(`Latest version: ${latestAfter}\n`);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
if (installedAfter && latestAfter && installedAfter === latestAfter) {
|
|
828
|
+
process.stdout.write("You are on the latest version.\n");
|
|
829
|
+
return;
|
|
830
|
+
}
|
|
831
|
+
|
|
832
|
+
if (latestAfter) {
|
|
833
|
+
process.stderr.write("Update completed, but this running install is not on the latest version yet.\n");
|
|
834
|
+
process.exitCode = 1;
|
|
835
|
+
return;
|
|
836
|
+
}
|
|
837
|
+
|
|
838
|
+
process.stdout.write("Could not verify latest version from npm, but update command completed.\n");
|
|
839
|
+
}
|
|
840
|
+
|
|
699
841
|
function sleepSync(ms) {
|
|
700
842
|
const durationMs = Math.max(0, Number(ms) || 0);
|
|
701
843
|
if (durationMs <= 0) {
|
|
@@ -1288,6 +1430,8 @@ function printUsage() {
|
|
|
1288
1430
|
process.stdout.write(" Example: timer 5 min 2 sec\n\n");
|
|
1289
1431
|
process.stdout.write("Settings\n");
|
|
1290
1432
|
process.stdout.write(" timer settings\n\n");
|
|
1433
|
+
process.stdout.write("Update\n");
|
|
1434
|
+
process.stdout.write(" timer update\n\n");
|
|
1291
1435
|
process.stdout.write("Controls\n");
|
|
1292
1436
|
process.stdout.write(" Defaults: p/Space Pause-Resume | r Restart | f Random Style | q/e/Ctrl+C Exit\n");
|
|
1293
1437
|
process.stdout.write(" Keybindings are customizable in `timer settings`.\n\n");
|
|
@@ -1316,6 +1460,11 @@ function runTimer(args) {
|
|
|
1316
1460
|
return;
|
|
1317
1461
|
}
|
|
1318
1462
|
|
|
1463
|
+
if (args[0] === "update") {
|
|
1464
|
+
runSelfUpdate();
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
|
|
1319
1468
|
if (args[0] === "style") {
|
|
1320
1469
|
if (args.length === 1 || (args.length === 2 && args[1] === "--all")) {
|
|
1321
1470
|
const currentFont = getFontFromConfig();
|