@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.
Files changed (3) hide show
  1. package/README.md +14 -17
  2. package/dist/index.js +169 -11
  3. 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
- Session is persisted automatically after login:
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 (Linux/macOS)
94
- %APPDATA%\kuma-cli-nodejs\Config (Windows)
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": "<session-token>"
98
+ "token": "***"
101
99
  }
102
100
  ```
103
101
 
104
- Run `kuma status` to see the config path on your system.
102
+ Run `kuma status` to see the exact config path on your machine.
105
103
 
106
104
  ## Architecture
107
105
 
108
- Uses Uptime Kuma's native **Socket.IO API** — no REST API, no hacks. The same protocol the web UI uses.
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 socket.emit("login") receives token
112
- kuma * socket.emit("loginByToken") authenticated session
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 # Entry point, CLI setup
132
- ├── client.ts # Socket.IO connection + auth
133
- ├── config.ts # ~/.kuma-cli.json persistence
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 # Table rendering, chalk helpers
142
- └── errors.ts # Error formatting + exit codes
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 = require("supports-color");
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 require_has_flag = __commonJS({
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 = require_has_flag();
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 uptime events immediately on connect (before
27579
- // getMonitorList is called), so we buffer them for later use.
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
- async getHeartbeatList(monitorId, period) {
27800
- this.socket.emit("getHeartbeatList", monitorId, period ?? 24);
27801
- const result = await this.waitFor("heartbeatList");
27802
- return result.data ?? [];
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.socket.emit("getStatusPageList");
27806
- return this.waitFor("statusPageList");
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": "0.1.0",
3
+ "version": "1.0.0",
4
4
  "description": "CLI for managing Uptime Kuma via Socket.IO API",
5
5
  "bin": {
6
- "kuma": "./dist/index.js"
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
  }