Skip to content

Commit 7f1b9db

Browse files
committed
feat: added wakatime, dotenv reload and update mem monitor
1 parent 95d7213 commit 7f1b9db

6 files changed

Lines changed: 112 additions & 13 deletions

File tree

.env.example

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,4 +75,8 @@ QUERY_CACHING_TTL=3600
7575

7676
# the shell to use for executing commands
7777
# this should be a valid shell path, e.g., /bin/bash, /bin/zsh
78-
EXEC_SHELL=/bin/bash
78+
EXEC_SHELL=/bin/bash
79+
80+
# Your Wakatime API keys
81+
# (optional) else the wakatime command aint going to work
82+
WAKATIME_API_KEY=

src/commands/env.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { Message } from "../../types/message";
2+
import log from "../components/utils/log";
3+
import dotenv from "dotenv";
4+
5+
export const info = {
6+
command: "env",
7+
description:
8+
"Get all new process.env and append them into the project without restarting.",
9+
usage: "env",
10+
example: "env",
11+
role: "user",
12+
cooldown: 5000,
13+
};
14+
15+
export default async function (msg: Message) {
16+
if (!/^env/i.test(msg.body)) return;
17+
18+
dotenv.config({ override: true });
19+
20+
await msg.reply("Dotenv override successfully.");
21+
}

src/commands/reload.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ export const info = {
1111
description: "Reload a specific command or all commands.",
1212
usage: "reload [command]",
1313
example: "reload ai",
14-
role: "admin",
14+
role: "user",
1515
cooldown: 5000,
1616
};
1717

src/commands/update.ts

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,22 +11,18 @@ export const info = {
1111
description: "Pull changes from the remote repository.",
1212
usage: "update",
1313
example: "update",
14-
role: "admin",
14+
role: "user",
1515
cooldown: 5000,
1616
};
1717

1818
const execPromise = util.promisify(exec);
1919

2020
export default async function (msg: Message) {
21-
try {
22-
const { stdout, stderr } = await execPromise("git pull");
21+
if (!/^update/i.test(msg.body)) return;
22+
const { stdout, stderr } = await execPromise("git pull");
2323

24-
if (stdout) log.info("Update", `git pull stdout:\n${stdout}`);
25-
if (stderr) log.warn("Update", `git pull stderr:\n${stderr}`);
24+
if (stdout) log.info("Update", `git pull stdout:\n${stdout}`);
25+
if (stderr) log.warn("Update", `git pull stderr:\n${stderr}`);
2626

27-
await msg.reply(stdout || stderr);
28-
} catch (error: any) {
29-
log.error("Update", `git pull failed: ${error.message}`);
30-
await msg.reply("Failed to update repository. Check logs.");
31-
}
27+
await msg.reply(stdout || stderr);
3228
}

src/commands/wakatime.ts

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
import { Message } from "../../types/message";
2+
import log from "../components/utils/log";
3+
import axios from "axios";
4+
5+
export const info = {
6+
command: "wakatime",
7+
description: "Shows current WakaTime tasks for today.",
8+
usage: "wakatime",
9+
example: "wakatime",
10+
role: "user",
11+
cooldown: 5000,
12+
};
13+
14+
export default async function (msg: Message) {
15+
if (!/^wakatime/i.test(msg.body)) return;
16+
17+
const apiKey = process.env.WAKATIME_API_KEY;
18+
if (!apiKey) {
19+
await msg.reply("WakaTime API key is not configured.");
20+
return;
21+
}
22+
23+
const today = new Date().toISOString().split("T")[0]; // YYYY-MM-DD
24+
25+
const response = await axios.get(
26+
`https://wakatime.com/api/v1/users/current/heartbeats`,
27+
{
28+
params: { date: today },
29+
headers: {
30+
Authorization: `Basic ${Buffer.from(apiKey + ":").toString("base64")}`,
31+
},
32+
},
33+
);
34+
35+
const heartbeats = response.data.data;
36+
if (!heartbeats || heartbeats.length === 0) {
37+
await msg.reply("The author didn't do any job today unfortunately 😢");
38+
return;
39+
}
40+
41+
// Sort by time
42+
heartbeats.sort((a: any, b: any) => a.time - b.time);
43+
44+
const projectDurations: Record<string, number> = {};
45+
46+
for (let i = 0; i < heartbeats.length; i++) {
47+
const hb = heartbeats[i];
48+
const nextHb = heartbeats[i + 1];
49+
50+
if (!hb.project) continue;
51+
52+
let duration = 0;
53+
if (nextHb) {
54+
duration = Math.min(120, nextHb.time - hb.time); // max 2 minutes per heartbeat
55+
} else {
56+
duration = 60; // assume 1 minute for last heartbeat
57+
}
58+
59+
projectDurations[hb.project] =
60+
(projectDurations[hb.project] || 0) + duration;
61+
}
62+
63+
const projects = Object.keys(projectDurations);
64+
if (projects.length === 0) {
65+
await msg.reply("The author didn't do any job today unfortunately 😢");
66+
return;
67+
}
68+
69+
const projectList = projects.map((proj) => {
70+
const seconds = projectDurations[proj];
71+
const hours = Math.floor(seconds / 3600);
72+
const minutes = Math.floor((seconds % 3600) / 60);
73+
return `- ${proj}: ${hours}h ${minutes}m`;
74+
});
75+
76+
const replyText = `\`Today's WakaTime projects\`\n${projectList.join("\n")}`;
77+
await msg.reply(replyText);
78+
}

src/components/utils/memMonitor.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class MemoryMonitor {
4747

4848
// Oh shit!
4949
if (this.history.length > 5) {
50-
const lastFive = this.history.slice(-5).map((h) => h.usedMB);
50+
const lastFive = this.history.slice(-5).map((h) => h.usedMB && h.usedMB > this.thresholdMB);
5151
if (lastFive.every((val, i, arr) => i === 0 || val > arr[i - 1])) {
5252
log.warn(
5353
"MemoryMonitor",

0 commit comments

Comments
 (0)