@blackasteroid/kuma-cli 0.1.0 → 1.0.0
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 +14 -17
- package/dist/index.js +169 -11
- package/package.json +13 -4
package/README.md
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
# kuma-cli
|
|
2
2
|
|
|
3
|
-
> CLI for managing [Uptime Kuma](https://github.com/louislam/uptime-kuma) via its native Socket.IO API.
|
|
4
|
-
|
|
5
|
-
No more clicking through the web panel — manage monitors, status pages, and heartbeats directly from your terminal.
|
|
3
|
+
> CLI for managing [Uptime Kuma](https://github.com/louislam/uptime-kuma) via its native Socket.IO API. No more clicking through the web panel — manage monitors, status pages, and heartbeats directly from your terminal.
|
|
6
4
|
|
|
7
5
|
## Install
|
|
8
6
|
|
|
@@ -87,29 +85,29 @@ kuma monitors add --name "My API" --type http --url https://api.example.com
|
|
|
87
85
|
|
|
88
86
|
## Config
|
|
89
87
|
|
|
90
|
-
|
|
88
|
+
After login, your session is saved automatically — you won't need to re-authenticate on every command:
|
|
91
89
|
|
|
92
90
|
```
|
|
93
|
-
~/.config/kuma-cli-nodejs/config.json
|
|
94
|
-
%APPDATA%\kuma-cli-nodejs\Config
|
|
91
|
+
~/.config/kuma-cli-nodejs/config.json (Linux/macOS)
|
|
92
|
+
%APPDATA%\kuma-cli-nodejs\Config (Windows)
|
|
95
93
|
```
|
|
96
94
|
|
|
97
95
|
```json
|
|
98
96
|
{
|
|
99
97
|
"url": "https://kuma.example.com",
|
|
100
|
-
"token": "
|
|
98
|
+
"token": "***"
|
|
101
99
|
}
|
|
102
100
|
```
|
|
103
101
|
|
|
104
|
-
Run `kuma status` to see the config path on your
|
|
102
|
+
Run `kuma status` to see the exact config path on your machine.
|
|
105
103
|
|
|
106
104
|
## Architecture
|
|
107
105
|
|
|
108
|
-
|
|
106
|
+
kuma-cli talks to Uptime Kuma through its native **Socket.IO API** — the same protocol the web UI uses. No REST shims, no scraping, no hacks.
|
|
109
107
|
|
|
110
108
|
```
|
|
111
|
-
kuma login
|
|
112
|
-
kuma *
|
|
109
|
+
kuma login → socket.emit("login") → receives token
|
|
110
|
+
kuma * → socket.emit("loginByToken") → authenticated session
|
|
113
111
|
```
|
|
114
112
|
|
|
115
113
|
## Development
|
|
@@ -118,7 +116,6 @@ kuma * → socket.emit("loginByToken") → authenticated session
|
|
|
118
116
|
git clone https://github.com/BlackAsteroid/kuma-cli
|
|
119
117
|
cd kuma-cli
|
|
120
118
|
npm install
|
|
121
|
-
|
|
122
119
|
npm run dev # watch mode (tsup)
|
|
123
120
|
npm run build # compile to dist/
|
|
124
121
|
npm run typecheck # tsc --noEmit
|
|
@@ -128,9 +125,9 @@ npm run typecheck # tsc --noEmit
|
|
|
128
125
|
|
|
129
126
|
```
|
|
130
127
|
src/
|
|
131
|
-
├── index.ts
|
|
132
|
-
├── client.ts
|
|
133
|
-
├── config.ts
|
|
128
|
+
├── index.ts # Entry point, CLI setup
|
|
129
|
+
├── client.ts # Socket.IO connection + auth
|
|
130
|
+
├── config.ts # ~/.kuma-cli.json persistence
|
|
134
131
|
├── commands/
|
|
135
132
|
│ ├── login.ts
|
|
136
133
|
│ ├── logout.ts
|
|
@@ -138,8 +135,8 @@ src/
|
|
|
138
135
|
│ ├── status-pages.ts
|
|
139
136
|
│ └── heartbeat.ts
|
|
140
137
|
└── utils/
|
|
141
|
-
├── output.ts
|
|
142
|
-
└── errors.ts
|
|
138
|
+
├── output.ts # Table rendering, chalk helpers
|
|
139
|
+
└── errors.ts # Error formatting + exit codes
|
|
143
140
|
```
|
|
144
141
|
|
|
145
142
|
## License
|
package/dist/index.js
CHANGED
|
@@ -8883,6 +8883,121 @@ var require_browser = __commonJS({
|
|
|
8883
8883
|
}
|
|
8884
8884
|
});
|
|
8885
8885
|
|
|
8886
|
+
// node_modules/has-flag/index.js
|
|
8887
|
+
var require_has_flag = __commonJS({
|
|
8888
|
+
"node_modules/has-flag/index.js"(exports2, module2) {
|
|
8889
|
+
"use strict";
|
|
8890
|
+
module2.exports = (flag, argv = process.argv) => {
|
|
8891
|
+
const prefix = flag.startsWith("-") ? "" : flag.length === 1 ? "-" : "--";
|
|
8892
|
+
const position = argv.indexOf(prefix + flag);
|
|
8893
|
+
const terminatorPosition = argv.indexOf("--");
|
|
8894
|
+
return position !== -1 && (terminatorPosition === -1 || position < terminatorPosition);
|
|
8895
|
+
};
|
|
8896
|
+
}
|
|
8897
|
+
});
|
|
8898
|
+
|
|
8899
|
+
// node_modules/supports-color/index.js
|
|
8900
|
+
var require_supports_color = __commonJS({
|
|
8901
|
+
"node_modules/supports-color/index.js"(exports2, module2) {
|
|
8902
|
+
"use strict";
|
|
8903
|
+
var os3 = require("os");
|
|
8904
|
+
var tty2 = require("tty");
|
|
8905
|
+
var hasFlag2 = require_has_flag();
|
|
8906
|
+
var { env: env3 } = process;
|
|
8907
|
+
var forceColor;
|
|
8908
|
+
if (hasFlag2("no-color") || hasFlag2("no-colors") || hasFlag2("color=false") || hasFlag2("color=never")) {
|
|
8909
|
+
forceColor = 0;
|
|
8910
|
+
} else if (hasFlag2("color") || hasFlag2("colors") || hasFlag2("color=true") || hasFlag2("color=always")) {
|
|
8911
|
+
forceColor = 1;
|
|
8912
|
+
}
|
|
8913
|
+
if ("FORCE_COLOR" in env3) {
|
|
8914
|
+
if (env3.FORCE_COLOR === "true") {
|
|
8915
|
+
forceColor = 1;
|
|
8916
|
+
} else if (env3.FORCE_COLOR === "false") {
|
|
8917
|
+
forceColor = 0;
|
|
8918
|
+
} else {
|
|
8919
|
+
forceColor = env3.FORCE_COLOR.length === 0 ? 1 : Math.min(parseInt(env3.FORCE_COLOR, 10), 3);
|
|
8920
|
+
}
|
|
8921
|
+
}
|
|
8922
|
+
function translateLevel2(level) {
|
|
8923
|
+
if (level === 0) {
|
|
8924
|
+
return false;
|
|
8925
|
+
}
|
|
8926
|
+
return {
|
|
8927
|
+
level,
|
|
8928
|
+
hasBasic: true,
|
|
8929
|
+
has256: level >= 2,
|
|
8930
|
+
has16m: level >= 3
|
|
8931
|
+
};
|
|
8932
|
+
}
|
|
8933
|
+
function supportsColor2(haveStream, streamIsTTY) {
|
|
8934
|
+
if (forceColor === 0) {
|
|
8935
|
+
return 0;
|
|
8936
|
+
}
|
|
8937
|
+
if (hasFlag2("color=16m") || hasFlag2("color=full") || hasFlag2("color=truecolor")) {
|
|
8938
|
+
return 3;
|
|
8939
|
+
}
|
|
8940
|
+
if (hasFlag2("color=256")) {
|
|
8941
|
+
return 2;
|
|
8942
|
+
}
|
|
8943
|
+
if (haveStream && !streamIsTTY && forceColor === void 0) {
|
|
8944
|
+
return 0;
|
|
8945
|
+
}
|
|
8946
|
+
const min = forceColor || 0;
|
|
8947
|
+
if (env3.TERM === "dumb") {
|
|
8948
|
+
return min;
|
|
8949
|
+
}
|
|
8950
|
+
if (process.platform === "win32") {
|
|
8951
|
+
const osRelease = os3.release().split(".");
|
|
8952
|
+
if (Number(osRelease[0]) >= 10 && Number(osRelease[2]) >= 10586) {
|
|
8953
|
+
return Number(osRelease[2]) >= 14931 ? 3 : 2;
|
|
8954
|
+
}
|
|
8955
|
+
return 1;
|
|
8956
|
+
}
|
|
8957
|
+
if ("CI" in env3) {
|
|
8958
|
+
if (["TRAVIS", "CIRCLECI", "APPVEYOR", "GITLAB_CI", "GITHUB_ACTIONS", "BUILDKITE"].some((sign) => sign in env3) || env3.CI_NAME === "codeship") {
|
|
8959
|
+
return 1;
|
|
8960
|
+
}
|
|
8961
|
+
return min;
|
|
8962
|
+
}
|
|
8963
|
+
if ("TEAMCITY_VERSION" in env3) {
|
|
8964
|
+
return /^(9\.(0*[1-9]\d*)\.|\d{2,}\.)/.test(env3.TEAMCITY_VERSION) ? 1 : 0;
|
|
8965
|
+
}
|
|
8966
|
+
if (env3.COLORTERM === "truecolor") {
|
|
8967
|
+
return 3;
|
|
8968
|
+
}
|
|
8969
|
+
if ("TERM_PROGRAM" in env3) {
|
|
8970
|
+
const version = parseInt((env3.TERM_PROGRAM_VERSION || "").split(".")[0], 10);
|
|
8971
|
+
switch (env3.TERM_PROGRAM) {
|
|
8972
|
+
case "iTerm.app":
|
|
8973
|
+
return version >= 3 ? 3 : 2;
|
|
8974
|
+
case "Apple_Terminal":
|
|
8975
|
+
return 2;
|
|
8976
|
+
}
|
|
8977
|
+
}
|
|
8978
|
+
if (/-256(color)?$/i.test(env3.TERM)) {
|
|
8979
|
+
return 2;
|
|
8980
|
+
}
|
|
8981
|
+
if (/^screen|^xterm|^vt100|^vt220|^rxvt|color|ansi|cygwin|linux/i.test(env3.TERM)) {
|
|
8982
|
+
return 1;
|
|
8983
|
+
}
|
|
8984
|
+
if ("COLORTERM" in env3) {
|
|
8985
|
+
return 1;
|
|
8986
|
+
}
|
|
8987
|
+
return min;
|
|
8988
|
+
}
|
|
8989
|
+
function getSupportLevel(stream) {
|
|
8990
|
+
const level = supportsColor2(stream, stream && stream.isTTY);
|
|
8991
|
+
return translateLevel2(level);
|
|
8992
|
+
}
|
|
8993
|
+
module2.exports = {
|
|
8994
|
+
supportsColor: getSupportLevel,
|
|
8995
|
+
stdout: translateLevel2(supportsColor2(true, tty2.isatty(1))),
|
|
8996
|
+
stderr: translateLevel2(supportsColor2(true, tty2.isatty(2)))
|
|
8997
|
+
};
|
|
8998
|
+
}
|
|
8999
|
+
});
|
|
9000
|
+
|
|
8886
9001
|
// node_modules/debug/src/node.js
|
|
8887
9002
|
var require_node = __commonJS({
|
|
8888
9003
|
"node_modules/debug/src/node.js"(exports2, module2) {
|
|
@@ -8902,7 +9017,7 @@ var require_node = __commonJS({
|
|
|
8902
9017
|
);
|
|
8903
9018
|
exports2.colors = [6, 2, 3, 4, 5, 1];
|
|
8904
9019
|
try {
|
|
8905
|
-
const supportsColor2 =
|
|
9020
|
+
const supportsColor2 = require_supports_color();
|
|
8906
9021
|
if (supportsColor2 && (supportsColor2.stderr || supportsColor2).level >= 2) {
|
|
8907
9022
|
exports2.colors = [
|
|
8908
9023
|
20,
|
|
@@ -22681,7 +22796,7 @@ var require_styles2 = __commonJS({
|
|
|
22681
22796
|
});
|
|
22682
22797
|
|
|
22683
22798
|
// node_modules/@colors/colors/lib/system/has-flag.js
|
|
22684
|
-
var
|
|
22799
|
+
var require_has_flag2 = __commonJS({
|
|
22685
22800
|
"node_modules/@colors/colors/lib/system/has-flag.js"(exports2, module2) {
|
|
22686
22801
|
"use strict";
|
|
22687
22802
|
module2.exports = function(flag, argv) {
|
|
@@ -22699,7 +22814,7 @@ var require_supports_colors = __commonJS({
|
|
|
22699
22814
|
"node_modules/@colors/colors/lib/system/supports-colors.js"(exports2, module2) {
|
|
22700
22815
|
"use strict";
|
|
22701
22816
|
var os3 = require("os");
|
|
22702
|
-
var hasFlag2 =
|
|
22817
|
+
var hasFlag2 = require_has_flag2();
|
|
22703
22818
|
var env3 = process.env;
|
|
22704
22819
|
var forceColor = void 0;
|
|
22705
22820
|
if (hasFlag2("no-color") || hasFlag2("no-colors") || hasFlag2("color=false")) {
|
|
@@ -27575,10 +27690,12 @@ Object.assign(lookup, {
|
|
|
27575
27690
|
// src/client.ts
|
|
27576
27691
|
var KumaClient = class {
|
|
27577
27692
|
constructor(url2) {
|
|
27578
|
-
// Kuma pushes heartbeatList and
|
|
27579
|
-
//
|
|
27693
|
+
// Kuma pushes heartbeatList, uptime, and statusPageList events immediately
|
|
27694
|
+
// on connect / after auth, so we buffer them for later use.
|
|
27580
27695
|
this.heartbeatCache = {};
|
|
27581
27696
|
this.uptimeCache = {};
|
|
27697
|
+
// BUG-02 fix: buffer statusPageList pushed by Kuma during afterLogin
|
|
27698
|
+
this.statusPageCache = null;
|
|
27582
27699
|
this.url = url2;
|
|
27583
27700
|
this.socket = lookup(url2, {
|
|
27584
27701
|
transports: ["websocket"],
|
|
@@ -27599,6 +27716,9 @@ var KumaClient = class {
|
|
|
27599
27716
|
this.uptimeCache[`${monitorId}_${period}`] = value2;
|
|
27600
27717
|
}
|
|
27601
27718
|
);
|
|
27719
|
+
this.socket.on("statusPageList", (data) => {
|
|
27720
|
+
this.statusPageCache = data;
|
|
27721
|
+
});
|
|
27602
27722
|
}
|
|
27603
27723
|
/**
|
|
27604
27724
|
* Wait for a server-pushed event (not a callback response).
|
|
@@ -27796,14 +27916,52 @@ var KumaClient = class {
|
|
|
27796
27916
|
);
|
|
27797
27917
|
});
|
|
27798
27918
|
}
|
|
27799
|
-
|
|
27800
|
-
|
|
27801
|
-
|
|
27802
|
-
|
|
27919
|
+
// BUG-01 fix: use the correct server event "getMonitorBeats" with a callback.
|
|
27920
|
+
// The old code emitted "getHeartbeatList" (which doesn't exist) and tried to
|
|
27921
|
+
// waitFor a "heartbeatList" push event — causing a timeout every time.
|
|
27922
|
+
// The correct API: socket.emit("getMonitorBeats", monitorID, periodHours, cb)
|
|
27923
|
+
// cb receives { ok: boolean, data: Heartbeat[] }
|
|
27924
|
+
async getHeartbeatList(monitorId, periodHours = 24) {
|
|
27925
|
+
return new Promise((resolve, reject) => {
|
|
27926
|
+
const timer = setTimeout(
|
|
27927
|
+
() => reject(new Error("getMonitorBeats timeout")),
|
|
27928
|
+
15e3
|
|
27929
|
+
);
|
|
27930
|
+
this.socket.emit(
|
|
27931
|
+
"getMonitorBeats",
|
|
27932
|
+
monitorId,
|
|
27933
|
+
periodHours,
|
|
27934
|
+
(result) => {
|
|
27935
|
+
clearTimeout(timer);
|
|
27936
|
+
if (!result.ok) {
|
|
27937
|
+
reject(new Error(result.msg ?? "Failed to fetch heartbeats"));
|
|
27938
|
+
return;
|
|
27939
|
+
}
|
|
27940
|
+
resolve(result.data ?? []);
|
|
27941
|
+
}
|
|
27942
|
+
);
|
|
27943
|
+
});
|
|
27803
27944
|
}
|
|
27945
|
+
// BUG-02 fix: statusPageList is pushed by Kuma automatically during afterLogin,
|
|
27946
|
+
// not as a response to any explicit emit. The old code registered a waitFor
|
|
27947
|
+
// listener *after* the push had already fired, causing a guaranteed timeout.
|
|
27948
|
+
// Fix: buffer the push in the constructor and return the cache here.
|
|
27949
|
+
// If the cache is still null after auth (e.g. no status pages exist), fall back
|
|
27950
|
+
// to a short waitFor so we don't hang forever.
|
|
27804
27951
|
async getStatusPageList() {
|
|
27805
|
-
this.
|
|
27806
|
-
|
|
27952
|
+
if (this.statusPageCache !== null) {
|
|
27953
|
+
return this.statusPageCache;
|
|
27954
|
+
}
|
|
27955
|
+
return new Promise((resolve) => {
|
|
27956
|
+
const timer = setTimeout(() => {
|
|
27957
|
+
resolve({});
|
|
27958
|
+
}, 5e3);
|
|
27959
|
+
this.socket.once("statusPageList", (data) => {
|
|
27960
|
+
clearTimeout(timer);
|
|
27961
|
+
this.statusPageCache = data;
|
|
27962
|
+
resolve(data);
|
|
27963
|
+
});
|
|
27964
|
+
});
|
|
27807
27965
|
}
|
|
27808
27966
|
disconnect() {
|
|
27809
27967
|
this.socket.disconnect();
|
package/package.json
CHANGED
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@blackasteroid/kuma-cli",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "1.0.0",
|
|
4
4
|
"description": "CLI for managing Uptime Kuma via Socket.IO API",
|
|
5
5
|
"bin": {
|
|
6
|
-
"kuma": "
|
|
6
|
+
"kuma": "dist/index.js"
|
|
7
7
|
},
|
|
8
8
|
"main": "./dist/index.js",
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsup",
|
|
11
11
|
"dev": "tsup --watch",
|
|
12
12
|
"typecheck": "tsc --noEmit",
|
|
13
|
-
"prepublishOnly": "npm run build"
|
|
13
|
+
"prepublishOnly": "npm run build",
|
|
14
|
+
"release": "semantic-release",
|
|
15
|
+
"release:dry": "semantic-release --dry-run"
|
|
14
16
|
},
|
|
15
17
|
"keywords": [
|
|
16
18
|
"uptime-kuma",
|
|
@@ -21,7 +23,7 @@
|
|
|
21
23
|
"license": "MIT",
|
|
22
24
|
"repository": {
|
|
23
25
|
"type": "git",
|
|
24
|
-
"url": "https://github.com/BlackAsteroid/kuma-cli"
|
|
26
|
+
"url": "git+https://github.com/BlackAsteroid/kuma-cli.git"
|
|
25
27
|
},
|
|
26
28
|
"files": [
|
|
27
29
|
"dist/",
|
|
@@ -42,7 +44,14 @@
|
|
|
42
44
|
"socket.io-client": "^4.8.3"
|
|
43
45
|
},
|
|
44
46
|
"devDependencies": {
|
|
47
|
+
"@semantic-release/changelog": "^6.0.3",
|
|
48
|
+
"@semantic-release/exec": "^7.1.0",
|
|
49
|
+
"@semantic-release/git": "^10.0.1",
|
|
50
|
+
"@semantic-release/github": "^12.0.6",
|
|
51
|
+
"@semantic-release/npm": "^13.1.5",
|
|
45
52
|
"@types/node": "^25.5.0",
|
|
53
|
+
"conventional-changelog-conventionalcommits": "^9.3.0",
|
|
54
|
+
"semantic-release": "^25.0.3",
|
|
46
55
|
"tsup": "^8.5.1",
|
|
47
56
|
"typescript": "^5.9.3"
|
|
48
57
|
}
|