@josetra/dutic-mcp 0.1.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/LICENSE +21 -0
- package/README.md +223 -0
- package/dist/cli/format.js +69 -0
- package/dist/cli/format.js.map +1 -0
- package/dist/cli/index.js +426 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/setup.js +121 -0
- package/dist/cli/setup.js.map +1 -0
- package/dist/cli/ui.js +111 -0
- package/dist/cli/ui.js.map +1 -0
- package/dist/core/auth.js +47 -0
- package/dist/core/auth.js.map +1 -0
- package/dist/core/browser.js +56 -0
- package/dist/core/browser.js.map +1 -0
- package/dist/core/config.js +34 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/dates.js +43 -0
- package/dist/core/dates.js.map +1 -0
- package/dist/core/errors.js +25 -0
- package/dist/core/errors.js.map +1 -0
- package/dist/core/http.js +43 -0
- package/dist/core/http.js.map +1 -0
- package/dist/core/login.js +193 -0
- package/dist/core/login.js.map +1 -0
- package/dist/core/models.js +79 -0
- package/dist/core/models.js.map +1 -0
- package/dist/core/moodleClient.js +94 -0
- package/dist/core/moodleClient.js.map +1 -0
- package/dist/core/session.js +64 -0
- package/dist/core/session.js.map +1 -0
- package/dist/domain/assign.js +112 -0
- package/dist/domain/assign.js.map +1 -0
- package/dist/domain/concurrency.js +17 -0
- package/dist/domain/concurrency.js.map +1 -0
- package/dist/domain/courses.js +70 -0
- package/dist/domain/courses.js.map +1 -0
- package/dist/domain/documents.js +209 -0
- package/dist/domain/documents.js.map +1 -0
- package/dist/domain/grades.js +99 -0
- package/dist/domain/grades.js.map +1 -0
- package/dist/domain/people.js +161 -0
- package/dist/domain/people.js.map +1 -0
- package/dist/domain/resources.js +242 -0
- package/dist/domain/resources.js.map +1 -0
- package/dist/domain/tasks.js +191 -0
- package/dist/domain/tasks.js.map +1 -0
- package/dist/mcp/server.js +261 -0
- package/dist/mcp/server.js.map +1 -0
- package/package.json +67 -0
- package/skills/dutic/SKILL.md +173 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 JOSETRA44
|
|
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,223 @@
|
|
|
1
|
+
# dutic-mcp
|
|
2
|
+
|
|
3
|
+
**Servidor MCP + CLI para el aula virtual DUTIC (Moodle) de la UNSA.**
|
|
4
|
+
Tus tareas —incluidas las **ocultas**—, notas, materiales de estudio y compañeros, en la terminal
|
|
5
|
+
y disponibles para agentes de IA (Claude Code, Antigravity, OpenCode, mimocode…).
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
┌─────────────────────────────────────────────┐
|
|
9
|
+
│ 24 tareas · 10 SIN ENTREGAR │
|
|
10
|
+
│ 18 ocultas que el calendario no te muestra │
|
|
11
|
+
└─────────────────────────────────────────────┘
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Por qué existe
|
|
15
|
+
|
|
16
|
+
El timeline de Moodle sólo muestra tareas **accionables** (futuras y sin entregar). Las tareas sin
|
|
17
|
+
fecha de calendario, ya vencidas o ya entregadas **desaparecen de la vista** — y así se pierden
|
|
18
|
+
entregas. `dutic` barre todos los cursos, encuentra esas tareas, las marca como `OCULTA` y ordena
|
|
19
|
+
lo pendiente por urgencia.
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Instalación
|
|
24
|
+
|
|
25
|
+
**Requisitos:** [Node.js](https://nodejs.org) ≥ 20 y Google Chrome (o Edge) instalado.
|
|
26
|
+
No hace falta descargar Chromium: se usa el navegador que ya tienes.
|
|
27
|
+
|
|
28
|
+
### Un solo comando
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
npm install -g @joswetra/dutic-mcp
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Esto deja `dutic` y `dutic-mcp` en tu PATH.
|
|
35
|
+
|
|
36
|
+
<details>
|
|
37
|
+
<summary>Instalar desde el código fuente</summary>
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
git clone https://github.com/JOSETRA44/dutic-mcp.git
|
|
41
|
+
cd dutic-mcp
|
|
42
|
+
npm install # compila automáticamente (script prepare)
|
|
43
|
+
npm install -g . # deja los comandos en el PATH
|
|
44
|
+
```
|
|
45
|
+
</details>
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Primeros pasos
|
|
50
|
+
|
|
51
|
+
### 1. Configura tus agentes (una vez)
|
|
52
|
+
|
|
53
|
+
```bash
|
|
54
|
+
dutic setup
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Registra el servidor MCP en los agentes que tengas instalados y copia la skill `dutic` a sus
|
|
58
|
+
directorios. Hace copia de seguridad (`*.dutic-bak`) y **no toca** el resto de tu configuración.
|
|
59
|
+
|
|
60
|
+
```
|
|
61
|
+
[OK] Claude Code (MCP) C:\Users\tu-usuario\.claude.json
|
|
62
|
+
[OK] Antigravity (MCP) ...\.antigravity\config\mcp_config.json
|
|
63
|
+
[OK] OpenCode (MCP) ...\.config\opencode\opencode.jsonc
|
|
64
|
+
[OK] mimocode (MCP) ...\.config\mimocode\mimocode.jsonc
|
|
65
|
+
[OK] Claude Code (skill) ...\.claude\skills\dutic
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
> Reinicia cada agente para que cargue el servidor.
|
|
69
|
+
|
|
70
|
+
### 2. Inicia sesión (una vez)
|
|
71
|
+
|
|
72
|
+
```bash
|
|
73
|
+
dutic login
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
Se abre tu Chrome en el aula virtual. Pulsa **«Ingresar con Correo UNSA»**, elige tu cuenta de
|
|
77
|
+
Google y espera: la ventana se cierra sola al capturar la sesión. El perfil del navegador queda
|
|
78
|
+
guardado, así que las renovaciones posteriores suelen ser automáticas.
|
|
79
|
+
|
|
80
|
+
### 3. Compruébalo
|
|
81
|
+
|
|
82
|
+
```bash
|
|
83
|
+
dutic status # ¿sesión válida?
|
|
84
|
+
dutic tasks --all # tus tareas, incluidas las ocultas
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Si ves tus tareas, ya está todo listo. Pídeselo también a tu agente:
|
|
88
|
+
*«¿tengo alguna tarea pendiente en el aula virtual?»*
|
|
89
|
+
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
## Uso — CLI
|
|
93
|
+
|
|
94
|
+
| Comando | Qué hace |
|
|
95
|
+
|---|---|
|
|
96
|
+
| `dutic tasks` | Tareas próximas del timeline (rápido) |
|
|
97
|
+
| `dutic tasks --all` | **+ barrido de cursos → incluye las ocultas** |
|
|
98
|
+
| `dutic tasks --hidden` | Sólo las ocultas |
|
|
99
|
+
| `dutic task <cmid>` | Detalle: consigna, fechas, adjuntos, conflicto de fechas |
|
|
100
|
+
| `dutic grades [id]` | Notas: resumen de todos los cursos, o detalle de uno |
|
|
101
|
+
| `dutic courses` | Cursos matriculados |
|
|
102
|
+
| `dutic materials <id> [--section "Tema 2"]` | Archivos del curso, por unidad |
|
|
103
|
+
| `dutic study <id> [--section "Tema 2"]` | Baja materiales y convierte PDFs a Markdown |
|
|
104
|
+
| `dutic read <url>` | Lee un recurso (PDF→Markdown) para analizarlo |
|
|
105
|
+
| `dutic md <archivo.pdf>` | Convierte un PDF local a Markdown |
|
|
106
|
+
| `dutic people <id> [--email]` | Compañeros del curso (con correo) |
|
|
107
|
+
| `dutic person <texto>` | Busca a alguien por nombre o correo |
|
|
108
|
+
| `dutic teachers <id>` | Docentes del curso |
|
|
109
|
+
| `dutic pull <id>` | Descarga todos los materiales |
|
|
110
|
+
| `dutic setup` / `dutic login` / `dutic status` | Configuración y sesión |
|
|
111
|
+
|
|
112
|
+
Añade `--json` a la mayoría de comandos para salida estructurada.
|
|
113
|
+
|
|
114
|
+
### Ejemplos
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
# ¿Qué me falta entregar?
|
|
118
|
+
dutic tasks --all
|
|
119
|
+
|
|
120
|
+
# Preparar sólo la unidad que voy a estudiar
|
|
121
|
+
dutic study 2279 --section "Tema 2" --dest ./materiales
|
|
122
|
+
|
|
123
|
+
# ¿Qué pide exactamente esta tarea?
|
|
124
|
+
dutic task 385686
|
|
125
|
+
|
|
126
|
+
# El correo de mi compañero de grupo
|
|
127
|
+
dutic person "Piero"
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
---
|
|
131
|
+
|
|
132
|
+
## Uso — con agentes (MCP)
|
|
133
|
+
|
|
134
|
+
Tras `dutic setup` no hay nada más que hacer: pregúntale a tu agente por tus tareas, notas o
|
|
135
|
+
materiales y usará las herramientas del servidor.
|
|
136
|
+
|
|
137
|
+
<details>
|
|
138
|
+
<summary>Configuración manual (otros clientes MCP)</summary>
|
|
139
|
+
|
|
140
|
+
```json
|
|
141
|
+
{
|
|
142
|
+
"mcpServers": {
|
|
143
|
+
"dutic": {
|
|
144
|
+
"command": "dutic-mcp",
|
|
145
|
+
"env": { "DUTIC_SEMESTER": "2026A" }
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Si tu cliente no resuelve comandos del PATH, usa la ruta absoluta que imprime `dutic setup`:
|
|
152
|
+
`{ "command": "node", "args": ["<ruta>/dist/mcp/server.js"] }`
|
|
153
|
+
</details>
|
|
154
|
+
|
|
155
|
+
**19 herramientas**: tareas (`dutic_list_tasks`, `dutic_get_assignment_detail`, …), notas
|
|
156
|
+
(`dutic_get_grades`), materiales (`dutic_list_course_materials`, `dutic_study_course`,
|
|
157
|
+
`dutic_read_resource`, `dutic_pdf_to_markdown`), personas (`dutic_list_participants`,
|
|
158
|
+
`dutic_find_person`, `dutic_get_course_teachers`) y sesión.
|
|
159
|
+
|
|
160
|
+
---
|
|
161
|
+
|
|
162
|
+
## Configuración
|
|
163
|
+
|
|
164
|
+
| Variable | Para qué | Por defecto |
|
|
165
|
+
|---|---|---|
|
|
166
|
+
| `DUTIC_SEMESTER` | Semestre en la URL del aula (`2026A`, `2026B`…) | `2026A` |
|
|
167
|
+
| `DUTIC_BROWSER_CHANNEL` | Navegador para el login: `chrome`, `msedge`, `chromium` | `chrome` |
|
|
168
|
+
| `DUTIC_DATA_DIR` | Dónde guardar sesión y perfil | `~/.dutic` |
|
|
169
|
+
|
|
170
|
+
El semestre sólo se usa para la URL de login: tras iniciar sesión **se auto-detecta** del propio
|
|
171
|
+
aula, así que al cambiar de período normalmente no hay que tocar nada.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
## Cómo funciona
|
|
176
|
+
|
|
177
|
+
No usa la API pública de web services (la UNSA la tiene bloqueada). Captura la cookie
|
|
178
|
+
`MoodleSession` y el token `sesskey` tras el login de Google (Playwright manejando tu Chrome) y con
|
|
179
|
+
ellos llama al endpoint AJAX interno de Moodle, complementado con scraping donde hace falta.
|
|
180
|
+
|
|
181
|
+
| Necesidad | Fuente | Estado |
|
|
182
|
+
|---|---|---|
|
|
183
|
+
| Descubrir todas las tareas | `core_courseformat_get_state` | ✅ |
|
|
184
|
+
| Cursos matriculados | `core_course_get_enrolled_courses_by_timeline_classification` | ✅ |
|
|
185
|
+
| Timeline y fechas | `core_calendar_get_action_events_by_timesort` | ✅ (sólo accionables) |
|
|
186
|
+
| Estado de entrega, consigna, adjuntos | scraping de `mod/assign/view.php` | ✅ |
|
|
187
|
+
| Notas | scraping de `grade/report/user/index.php` | ✅ |
|
|
188
|
+
| Personas y correos | scraping de `user/index.php` y `user/view.php` | ✅ |
|
|
189
|
+
| `core_course_get_contents`, `mod_assign_*`, `gradereport_*` | — | ❌ bloqueadas por la UNSA |
|
|
190
|
+
|
|
191
|
+
**Fechas contradictorias:** algunas consignas mencionan una fecha distinta a la configurada en
|
|
192
|
+
Moodle. `dutic task <cmid>` compara ambas y avisa (`dateConflict`) — es la causa típica de entregas
|
|
193
|
+
perdidas.
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Publicar en npm
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npm login # cuenta de npm
|
|
201
|
+
npm version patch # o minor / major
|
|
202
|
+
npm publish # el paquete es scoped y público (publishConfig.access)
|
|
203
|
+
git push --follow-tags
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
`prepublishOnly` compila antes de publicar y `files` limita el tarball a `dist/` y `skills/`.
|
|
207
|
+
|
|
208
|
+
> Si tu scope de npm no es `@joswetra`, cambia el campo `name` en `package.json` por
|
|
209
|
+
> `@tu-scope/dutic-mcp` (o un nombre sin scope que esté libre).
|
|
210
|
+
|
|
211
|
+
---
|
|
212
|
+
|
|
213
|
+
## Privacidad y seguridad
|
|
214
|
+
|
|
215
|
+
- La sesión (`~/.dutic/session.json`) y el perfil del navegador contienen credenciales de tu
|
|
216
|
+
cuenta: no se versionan y el archivo se crea con permisos restrictivos.
|
|
217
|
+
- El certificado de `aulavirtual.unsa.edu.pe` (CA privada de la UNSA) se acepta **sólo** para ese host.
|
|
218
|
+
- La herramienta accede únicamente a lo que tú ya ves en el aula. Donde Moodle oculta información
|
|
219
|
+
(docentes en el listado, compañeros de otros grupos) se respeta esa restricción.
|
|
220
|
+
|
|
221
|
+
## Licencia
|
|
222
|
+
|
|
223
|
+
MIT © JOSETRA44
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { c } from "./ui.js";
|
|
2
|
+
export function formatDate(epochSeconds) {
|
|
3
|
+
if (epochSeconds == null)
|
|
4
|
+
return "sin fecha";
|
|
5
|
+
const d = new Date(epochSeconds * 1000);
|
|
6
|
+
return d.toLocaleString("es-PE", {
|
|
7
|
+
day: "2-digit",
|
|
8
|
+
month: "2-digit",
|
|
9
|
+
year: "numeric",
|
|
10
|
+
hour: "2-digit",
|
|
11
|
+
minute: "2-digit",
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export function relativeDue(epochSeconds) {
|
|
15
|
+
if (epochSeconds == null)
|
|
16
|
+
return "";
|
|
17
|
+
const diffMs = epochSeconds * 1000 - Date.now();
|
|
18
|
+
const days = Math.round(diffMs / 86_400_000);
|
|
19
|
+
if (days < 0)
|
|
20
|
+
return `vencida hace ${Math.abs(days)}d`;
|
|
21
|
+
if (days === 0)
|
|
22
|
+
return "¡hoy!";
|
|
23
|
+
if (days === 1)
|
|
24
|
+
return "mañana";
|
|
25
|
+
return `en ${days}d`;
|
|
26
|
+
}
|
|
27
|
+
const SUBMISSION = {
|
|
28
|
+
submitted: c.green,
|
|
29
|
+
"not-submitted": c.boldRed,
|
|
30
|
+
graded: c.cyan,
|
|
31
|
+
unknown: c.gray,
|
|
32
|
+
};
|
|
33
|
+
const SUBMISSION_LABEL = {
|
|
34
|
+
submitted: "ENTREGADA",
|
|
35
|
+
"not-submitted": "SIN ENTREGAR",
|
|
36
|
+
graded: "CALIFICADA",
|
|
37
|
+
unknown: "—",
|
|
38
|
+
};
|
|
39
|
+
/**
|
|
40
|
+
* Renderiza una tarea como bloque de líneas alineadas. Marca de estado a la izquierda:
|
|
41
|
+
* ● (pendiente, rojo) resalta lo urgente sin emojis.
|
|
42
|
+
*/
|
|
43
|
+
export function formatTaskLine(t) {
|
|
44
|
+
const paint = SUBMISSION[t.submission] ?? c.gray;
|
|
45
|
+
const dot = t.submission === "not-submitted" ? c.boldRed("●") : c.gray("○");
|
|
46
|
+
const scope = t.hidden ? c.yellow("OCULTA") : c.dim("timeline");
|
|
47
|
+
const state = paint(SUBMISSION_LABEL[t.submission] ?? "—");
|
|
48
|
+
const grade = t.grade ? c.dim(` · nota ${t.grade}`) : "";
|
|
49
|
+
const due = `${formatDate(t.dueDate)}${t.dueDate != null ? c.dim(` (${relativeDue(t.dueDate)})`) : ""}`;
|
|
50
|
+
const lines = [
|
|
51
|
+
`${dot} ${c.bold(t.name)} ${c.gray("[")}${scope}${c.gray("]")}`,
|
|
52
|
+
` ${c.dim("curso:")} ${t.courseName}`,
|
|
53
|
+
` ${c.dim("entrega:")} ${due}`,
|
|
54
|
+
` ${c.dim("estado:")} ${state}${grade}`,
|
|
55
|
+
];
|
|
56
|
+
if (t.timeRemaining)
|
|
57
|
+
lines.push(` ${c.dim("resta:")} ${t.timeRemaining}`);
|
|
58
|
+
if (t.dateConflict) {
|
|
59
|
+
const mencionadas = t.datesInDescription.map((d) => d.text).join(", ");
|
|
60
|
+
lines.push(` ${c.boldRed("[!] OJO:")} la consigna menciona ${c.yellow(mencionadas)} — distinta a la fecha oficial`);
|
|
61
|
+
}
|
|
62
|
+
if (t.attachments.length) {
|
|
63
|
+
lines.push(` ${c.dim("adjuntos:")} ${t.attachments.map((a) => a.filename).join(", ")}`);
|
|
64
|
+
}
|
|
65
|
+
if (t.url)
|
|
66
|
+
lines.push(` ${c.gray(t.url)}`);
|
|
67
|
+
return lines.join("\n");
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/cli/format.ts"],"names":[],"mappings":"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"}
|