@anthuanvasquez/devlogs 1.0.1
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/CHANGELOG.md +15 -0
- package/LICENSE +21 -0
- package/README.md +123 -0
- package/index.js +165 -0
- package/package.json +45 -0
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
|
|
4
|
+
|
|
5
|
+
### [1.0.1](https://github.com/anthuanvasquez/dev-logs/compare/v1.0.0...v1.0.1) (2026-02-12)
|
|
6
|
+
|
|
7
|
+
## 1.0.0 (2026-02-12)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* add script to run commands across all projects from json list ([9961fb3](https://github.com/anthuanvasquez/dev-logs/commit/9961fb351c894ac2faf5b28bdbe231ee695b53fc))
|
|
13
|
+
* add telegram support and interactive destination prompt ([541a893](https://github.com/anthuanvasquez/dev-logs/commit/541a8931fafa84b594d75df1ee76570f19451aca))
|
|
14
|
+
* implement CLI arguments for date range and destination flags ([d9bffd8](https://github.com/anthuanvasquez/dev-logs/commit/d9bffd8f2aeba466c32ed2b5a0152fc983e8f762))
|
|
15
|
+
* initial commit with project structure and dependencies ([ea14907](https://github.com/anthuanvasquez/dev-logs/commit/ea14907ac92c00798d77270b3956914d3d4dc336))
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Anthuan Vásquez
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# devlogs 📝
|
|
2
|
+
|
|
3
|
+
<p align="center">
|
|
4
|
+
<img src="docs/logo.png" alt="devlogs Logo" width="200" style="image-rendering: pixelated;">
|
|
5
|
+
</p>
|
|
6
|
+
|
|
7
|
+
> Automated daily commit reports powered by Gemini AI, delivered to Discord and Telegram.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- 🔍 **Scans commits** from the current day.
|
|
12
|
+
- 🤖 **Generates a concise summary** using Google Gemini AI.
|
|
13
|
+
- 🚀 **Sends reports** to Discord Webhooks and/or Telegram Bots.
|
|
14
|
+
- interactive **CLI prompt** to choose destination if both are configured.
|
|
15
|
+
- 📦 **Supports multiple projects** via a script.
|
|
16
|
+
|
|
17
|
+
## Prerequisites
|
|
18
|
+
|
|
19
|
+
- **Node.js** (v18 or higher recommended)
|
|
20
|
+
- **Git** installed and available in PATH.
|
|
21
|
+
- A **Google Gemini API Key** (Get it [here](https://aistudio.google.com/)).
|
|
22
|
+
- A **Discord Webhook URL** (optional).
|
|
23
|
+
- A **Telegram Bot Token** and **Chat ID** (optional).
|
|
24
|
+
|
|
25
|
+
## Installation
|
|
26
|
+
|
|
27
|
+
### From NPM (Recommended)
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
npx devlogs
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### From Source
|
|
34
|
+
|
|
35
|
+
1. Clone the repository:
|
|
36
|
+
```bash
|
|
37
|
+
git clone https://github.com/anthuanvasquez/devlogs.git
|
|
38
|
+
cd devlogs
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
2. Install dependencies:
|
|
42
|
+
```bash
|
|
43
|
+
npm install
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
3. Link the package globally:
|
|
47
|
+
```bash
|
|
48
|
+
npm link
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
## Configuration
|
|
52
|
+
|
|
53
|
+
Create a `.env` file in the root of your project or where you intend to run the script (or set them as system environment variables):
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
# Required
|
|
57
|
+
GEMINI_API_KEY=your_gemini_api_key
|
|
58
|
+
|
|
59
|
+
# Optional (at least one is required)
|
|
60
|
+
DISCORD_WEBHOOK_URL=your_discord_webhook_url
|
|
61
|
+
TELEGRAM_BOT_TOKEN=your_telegram_bot_token
|
|
62
|
+
TELEGRAM_CHAT_ID=your_telegram_chat_id
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Usage
|
|
66
|
+
|
|
67
|
+
Navigate to any git repository and run:
|
|
68
|
+
`devlogs [today|yesterday] [--discord] [--telegram]`
|
|
69
|
+
|
|
70
|
+
```bash
|
|
71
|
+
# Default (today, ask if multiple targets)
|
|
72
|
+
devlogs
|
|
73
|
+
|
|
74
|
+
# Report for yesterday
|
|
75
|
+
devlogs yesterday
|
|
76
|
+
|
|
77
|
+
# Force send to Discord (skip prompt)
|
|
78
|
+
devlogs today --discord
|
|
79
|
+
|
|
80
|
+
# Force send to Telegram (skip prompt)
|
|
81
|
+
devlogs yesterday --telegram
|
|
82
|
+
|
|
83
|
+
# Send to both without prompt
|
|
84
|
+
devlogs --discord --telegram
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
If multiple destinations are configured, you will be prompted to choose:
|
|
88
|
+
`¿Dónde deseas enviar el reporte? (discord/telegram/ambos) [ambos]:`
|
|
89
|
+
|
|
90
|
+
### Running for Multiple Projects
|
|
91
|
+
|
|
92
|
+
You can create a `projects.json` file with an array of absolute paths to your projects:
|
|
93
|
+
|
|
94
|
+
```json
|
|
95
|
+
[
|
|
96
|
+
"/path/to/project-a",
|
|
97
|
+
"/path/to/project-b"
|
|
98
|
+
]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Then run the included script:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
./run-all-projects.sh
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
## Automating with Cron
|
|
108
|
+
|
|
109
|
+
To run it automatically every day at 6:00 PM:
|
|
110
|
+
|
|
111
|
+
1. Open your crontab:
|
|
112
|
+
```bash
|
|
113
|
+
crontab -e
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
2. Add the following line (adjust paths accordingly):
|
|
117
|
+
```bash
|
|
118
|
+
0 18 * * 1-5 /path/to/dev-logs/run-all-projects.sh >> /tmp/cron_devlogs.txt 2>&1
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## License
|
|
122
|
+
|
|
123
|
+
MIT
|
package/index.js
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import { GoogleGenerativeAI } from "@google/generative-ai";
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
import fs from "fs";
|
|
4
|
+
import path from "path";
|
|
5
|
+
import readline from "readline";
|
|
6
|
+
import 'dotenv/config';
|
|
7
|
+
|
|
8
|
+
const DISCORD_WEBHOOK_URL = process.env.DISCORD_WEBHOOK_URL;
|
|
9
|
+
const GEMINI_API_KEY = process.env.GEMINI_API_KEY;
|
|
10
|
+
const TELEGRAM_BOT_TOKEN = process.env.TELEGRAM_BOT_TOKEN;
|
|
11
|
+
const TELEGRAM_CHAT_ID = process.env.TELEGRAM_CHAT_ID;
|
|
12
|
+
|
|
13
|
+
const genAI = new GoogleGenerativeAI(GEMINI_API_KEY);
|
|
14
|
+
const model = genAI.getGenerativeModel({ model: "gemini-flash-lite-latest" });
|
|
15
|
+
|
|
16
|
+
async function sendToDiscord(message) {
|
|
17
|
+
if (!DISCORD_WEBHOOK_URL) return;
|
|
18
|
+
|
|
19
|
+
console.log("🚀 Enviando a Discord...");
|
|
20
|
+
|
|
21
|
+
await fetch(DISCORD_WEBHOOK_URL, {
|
|
22
|
+
method: 'POST',
|
|
23
|
+
headers: { 'Content-Type': 'application/json' },
|
|
24
|
+
body: JSON.stringify({ content: message })
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
console.log("✅ Reporte enviado a Discord con éxito.");
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
async function sendToTelegram(message) {
|
|
31
|
+
if (!TELEGRAM_BOT_TOKEN || !TELEGRAM_CHAT_ID) return;
|
|
32
|
+
|
|
33
|
+
console.log("✈️ Enviando a Telegram...");
|
|
34
|
+
|
|
35
|
+
const url = `https://api.telegram.org/bot${TELEGRAM_BOT_TOKEN}/sendMessage`;
|
|
36
|
+
|
|
37
|
+
await fetch(url, {
|
|
38
|
+
method: 'POST',
|
|
39
|
+
headers: { 'Content-Type': 'application/json' },
|
|
40
|
+
body: JSON.stringify({
|
|
41
|
+
chat_id: TELEGRAM_CHAT_ID,
|
|
42
|
+
text: message,
|
|
43
|
+
parse_mode: 'Markdown'
|
|
44
|
+
})
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
console.log("✅ Reporte enviado a Telegram con éxito.");
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function askQuestion(query) {
|
|
51
|
+
const rl = readline.createInterface({
|
|
52
|
+
input: process.stdin,
|
|
53
|
+
output: process.stdout,
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return new Promise(resolve => rl.question(query, ans => {
|
|
57
|
+
rl.close();
|
|
58
|
+
resolve(ans);
|
|
59
|
+
}));
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function main() {
|
|
63
|
+
try {
|
|
64
|
+
const projectRoot = process.cwd();
|
|
65
|
+
let projectName = "Proyecto Desconocido";
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const packageJson = JSON.parse(fs.readFileSync(path.join(projectRoot, 'package.json'), 'utf8'));
|
|
69
|
+
projectName = packageJson.name || path.basename(projectRoot);
|
|
70
|
+
} catch (e) {
|
|
71
|
+
projectName = path.basename(projectRoot);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
projectName = projectName.charAt(0).toUpperCase() + projectName.slice(1);
|
|
75
|
+
|
|
76
|
+
const args = process.argv.slice(2);
|
|
77
|
+
const when = args.includes('yesterday') ? 'yesterday' : 'today';
|
|
78
|
+
const forceDiscord = args.includes('--discord');
|
|
79
|
+
const forceTelegram = args.includes('--telegram');
|
|
80
|
+
|
|
81
|
+
const dateOptions = { weekday: 'long', day: 'numeric', month: 'long' };
|
|
82
|
+
const dateObj = new Date();
|
|
83
|
+
|
|
84
|
+
if (when === 'yesterday') {
|
|
85
|
+
dateObj.setDate(dateObj.getDate() - 1);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const dayName = dateObj.toLocaleDateString('es-ES', { weekday: 'long' });
|
|
89
|
+
const dayNum = dateObj.getDate();
|
|
90
|
+
const formattedDate = `${dayName.charAt(0).toUpperCase() + dayName.slice(1)} ${dayNum}`;
|
|
91
|
+
|
|
92
|
+
console.log(`🔍 Buscando commits de ${when === 'today' ? 'hoy' : 'ayer'} para: ${projectName}...`);
|
|
93
|
+
|
|
94
|
+
let commits = "";
|
|
95
|
+
|
|
96
|
+
try {
|
|
97
|
+
let gitCommand = 'git log --since="00:00" --oneline --no-merges';
|
|
98
|
+
if (when === 'yesterday') {
|
|
99
|
+
gitCommand = 'git log --since="yesterday 00:00" --until="today 00:00" --oneline --no-merges';
|
|
100
|
+
}
|
|
101
|
+
commits = execSync(gitCommand, { encoding: 'utf8' }).trim();
|
|
102
|
+
} catch (error) {
|
|
103
|
+
console.error("⚠️ No es un repositorio git o hubo un error.");
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
if (!commits) {
|
|
108
|
+
console.log(`✅ No hay commits ${when === 'today' ? 'hoy' : 'ayer'}. ¡A descansar!`);
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
const hasDiscord = !!DISCORD_WEBHOOK_URL;
|
|
113
|
+
const hasTelegram = !!(TELEGRAM_BOT_TOKEN && TELEGRAM_CHAT_ID);
|
|
114
|
+
|
|
115
|
+
if (!hasDiscord && !hasTelegram) {
|
|
116
|
+
throw new Error("❌ No se encontró configuración para Discord ni Telegram en el archivo .env");
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
let target = "";
|
|
120
|
+
|
|
121
|
+
if (forceDiscord || forceTelegram) {
|
|
122
|
+
if (forceDiscord && forceTelegram) target = "ambos";
|
|
123
|
+
else if (forceDiscord) target = "discord";
|
|
124
|
+
else target = "telegram";
|
|
125
|
+
} else if (hasDiscord && hasTelegram) {
|
|
126
|
+
const answer = await askQuestion("¿Dónde deseas enviar el reporte? (discord/telegram/ambos) [ambos]: ");
|
|
127
|
+
target = answer.toLowerCase().trim() || "ambos";
|
|
128
|
+
} else if (hasDiscord) {
|
|
129
|
+
target = "discord";
|
|
130
|
+
} else {
|
|
131
|
+
target = "telegram";
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
const prompt = `
|
|
135
|
+
Actúa como un Tech Lead conciso.
|
|
136
|
+
Tengo estos commits realizados ${when === 'today' ? 'hoy' : 'ayer'} en el proyecto "${projectName}":
|
|
137
|
+
|
|
138
|
+
${commits}
|
|
139
|
+
|
|
140
|
+
Genera un resumen muy breve en formato lista (markdown).
|
|
141
|
+
- Agrupa tareas similares.
|
|
142
|
+
- Usa emojis técnicos.
|
|
143
|
+
- Destaca si hubo corrección de bugs o nuevas features.
|
|
144
|
+
- NO pongas título, solo los bullets.
|
|
145
|
+
`;
|
|
146
|
+
|
|
147
|
+
console.log("🤖 Generando reporte con Gemini Flash...");
|
|
148
|
+
|
|
149
|
+
const result = await model.generateContent(prompt);
|
|
150
|
+
const aiSummary = result.response.text();
|
|
151
|
+
const finalMessage = `## 📝 Resumen Diario - ${formattedDate} - ${projectName}\n\n${aiSummary}`;
|
|
152
|
+
|
|
153
|
+
if (target === "discord" || target === "ambos") {
|
|
154
|
+
await sendToDiscord(finalMessage);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
if (target === "telegram" || target === "ambos") {
|
|
158
|
+
await sendToTelegram(finalMessage);
|
|
159
|
+
}
|
|
160
|
+
} catch (error) {
|
|
161
|
+
console.error("❌ Error:", error.message || error);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
main();
|
package/package.json
ADDED
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@anthuanvasquez/devlogs",
|
|
3
|
+
"description": "Genera reportes diarios de commits y envialos a Discord",
|
|
4
|
+
"version": "1.0.1",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"devlogs": "./index.js"
|
|
8
|
+
},
|
|
9
|
+
"keywords": [
|
|
10
|
+
"git",
|
|
11
|
+
"report",
|
|
12
|
+
"ai",
|
|
13
|
+
"gemini",
|
|
14
|
+
"discord",
|
|
15
|
+
"telegram",
|
|
16
|
+
"developer",
|
|
17
|
+
"tools"
|
|
18
|
+
],
|
|
19
|
+
"author": "Anthuan Vasquez",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "git+https://github.com/anthuanvasquez/dev-logs.git"
|
|
24
|
+
},
|
|
25
|
+
"bugs": {
|
|
26
|
+
"url": "https://github.com/anthuanvasquez/dev-logs/issues"
|
|
27
|
+
},
|
|
28
|
+
"homepage": "https://github.com/anthuanvasquez/dev-logs#readme",
|
|
29
|
+
"type": "module",
|
|
30
|
+
"scripts": {
|
|
31
|
+
"test": "echo \"Error: no test specified\" && exit 1",
|
|
32
|
+
"release": "standard-version",
|
|
33
|
+
"release:minor": "standard-version --release-as minor",
|
|
34
|
+
"release:patch": "standard-version --release-as patch",
|
|
35
|
+
"release:major": "standard-version --release-as major",
|
|
36
|
+
"publish": "npm publish --access public"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@google/generative-ai": "^0.24.1",
|
|
40
|
+
"dotenv": "^17.2.4"
|
|
41
|
+
},
|
|
42
|
+
"devDependencies": {
|
|
43
|
+
"standard-version": "^9.5.0"
|
|
44
|
+
}
|
|
45
|
+
}
|