xonecode 0.14.1 → 0.17.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/THIRD_PARTY_NOTICES.md +2 -2
- package/apps/web/dist/assets/index-CnskHXof.js +485 -0
- package/apps/web/dist/assets/index-DLfF2uEK.css +1 -0
- package/apps/web/dist/assets/{php-KZMIPXrN.js → php-8TR3jUGL.js} +1 -1
- package/apps/web/dist/assets/{ruby-jf5bWc_X.js → ruby-IynpAZS-.js} +1 -1
- package/apps/web/dist/index.html +2 -2
- package/dist/agent/conectores/gestorJira.js +164 -0
- package/dist/agent/conectores/gestorJira.js.map +1 -0
- package/dist/agent/conectores/gestorNotion.js +365 -0
- package/dist/agent/conectores/gestorNotion.js.map +1 -0
- package/dist/agent/conectores/servicioDeConectores.js +135 -34
- package/dist/agent/conectores/servicioDeConectores.js.map +1 -1
- package/dist/agent/config/configEnDisco.js +28 -0
- package/dist/agent/config/configEnDisco.js.map +1 -1
- package/dist/agent/config/selectorEnMaquina.js +9 -2
- package/dist/agent/config/selectorEnMaquina.js.map +1 -1
- package/dist/agent/config/settingsEnDisco.js +41 -1
- package/dist/agent/config/settingsEnDisco.js.map +1 -1
- package/dist/agent/grafo/marcarCriteriosDelPlan.js +85 -0
- package/dist/agent/grafo/marcarCriteriosDelPlan.js.map +1 -0
- package/dist/agent/grafo/xoneAgent.js +4 -0
- package/dist/agent/grafo/xoneAgent.js.map +1 -1
- package/dist/agent/motores/trueforge/sesionTrueforge.js +3 -0
- package/dist/agent/motores/trueforge/sesionTrueforge.js.map +1 -1
- package/dist/agent/sesiones/checkpointer.js +18 -0
- package/dist/agent/sesiones/checkpointer.js.map +1 -1
- package/dist/agent/sesiones/modeloDelCambio.js +5 -2
- package/dist/agent/sesiones/modeloDelCambio.js.map +1 -1
- package/dist/agent/sesiones/sesionGit.js +5 -1
- package/dist/agent/sesiones/sesionGit.js.map +1 -1
- package/dist/agent/subagentes/agentesEnDisco.js +13 -4
- package/dist/agent/subagentes/agentesEnDisco.js.map +1 -1
- package/dist/core/config.js +71 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/gestorDeTareas.js +202 -0
- package/dist/core/gestorDeTareas.js.map +1 -0
- package/dist/core/ports.js +43 -0
- package/dist/core/ports.js.map +1 -1
- package/dist/core/selectorDeCarpeta.js +12 -2
- package/dist/core/selectorDeCarpeta.js.map +1 -1
- package/dist/core/settings.js +38 -4
- package/dist/core/settings.js.map +1 -1
- package/dist/core/tareasDelPlan.js +66 -0
- package/dist/core/tareasDelPlan.js.map +1 -1
- package/dist/web/servidor/arranque.js +840 -36
- package/dist/web/servidor/arranque.js.map +1 -1
- package/dist/web/servidor/datosDeCierre.js +37 -0
- package/dist/web/servidor/datosDeCierre.js.map +1 -0
- package/dist/web/servidor/sesiones.js +20 -0
- package/dist/web/servidor/sesiones.js.map +1 -1
- package/dist/web/servidor/transporte.js.map +1 -1
- package/dist/web/servidor/vestibulo.js +79 -5
- package/dist/web/servidor/vestibulo.js.map +1 -1
- package/package.json +1 -1
- package/skills/xone-plan-builder/SKILL.md +7 -2
- package/apps/web/dist/assets/index-CWAPXNAO.css +0 -1
- package/apps/web/dist/assets/index-KJGPIrNa.js +0 -485
package/apps/web/dist/index.html
CHANGED
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
<!-- El icono oficial, servido por Vite desde `iconos/`. Es el mismo fichero que la
|
|
8
8
|
marca de la barra superior: dos copias del logo acaban siendo dos logos. -->
|
|
9
9
|
<link rel="icon" type="image/png" href="./iconos/xonecode.png" />
|
|
10
|
-
<script type="module" crossorigin src="./assets/index-
|
|
11
|
-
<link rel="stylesheet" crossorigin href="./assets/index-
|
|
10
|
+
<script type="module" crossorigin src="./assets/index-CnskHXof.js"></script>
|
|
11
|
+
<link rel="stylesheet" crossorigin href="./assets/index-DLfF2uEK.css">
|
|
12
12
|
</head>
|
|
13
13
|
<!-- Sin el atributo aquí: el oscuro es SOLO del splash (el registro de entorno y
|
|
14
14
|
modelo), no de la consola entera — `App.tsx` lo pone y lo quita él mismo, en el
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El adaptador de Jira sobre `GestorDeTareasPort` (`core/gestorDeTareas.ts`): el ÚNICO fichero
|
|
3
|
+
* que conoce los nombres de las tools de Jira y la forma de sus respuestas — nada fuera de aquí
|
|
4
|
+
* sabe que el gestor de tareas es Jira.
|
|
5
|
+
*
|
|
6
|
+
* Llama al conector MCP por `llamar(nombre, args)` (el mismo `ServicioDeConectores.llamar`, ya
|
|
7
|
+
* atado a `"jira"` por quien construye este gestor): devuelve el TEXTO del primer bloque
|
|
8
|
+
* `type: "text"` del resultado. Este fichero solo hace `JSON.parse` de ese texto y lee sus
|
|
9
|
+
* campos a mano — nunca `@modelcontextprotocol` (`core/` no lo importa, y este fichero tampoco
|
|
10
|
+
* lo necesita).
|
|
11
|
+
*
|
|
12
|
+
* Lectura defensiva por campo, como `planesDelCable.ts` en el cliente: una respuesta que no es
|
|
13
|
+
* el JSON esperado LANZA, nunca vuelve como lista vacía (una lista vacía es un dato — «no hay
|
|
14
|
+
* pendientes» — y confundirlo con «no entendí la respuesta» esconde un fallo).
|
|
15
|
+
*
|
|
16
|
+
* Del `assignee` de Jira solo sale `displayName`: `emailAddress` y `accountId` no cruzan este
|
|
17
|
+
* adaptador (y por tanto no cruzan el cable).
|
|
18
|
+
*/
|
|
19
|
+
import { categoriaDeEstado, jqlDePendientes, motivoDeClaveDeProyecto, } from "../../core/gestorDeTareas.js";
|
|
20
|
+
/** El JSON del texto de una tool, o el error de «no se entiende» con el nombre de la tool que lo dio. */
|
|
21
|
+
function json(tool, texto) {
|
|
22
|
+
try {
|
|
23
|
+
return JSON.parse(texto);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
throw new Error(`Jira contestó algo que no se entiende (${tool})`);
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
function objeto(tool, valor) {
|
|
30
|
+
if (typeof valor !== "object" || valor === null)
|
|
31
|
+
throw new Error(`Jira contestó algo que no se entiende (${tool})`);
|
|
32
|
+
return valor;
|
|
33
|
+
}
|
|
34
|
+
function texto(tool, valor) {
|
|
35
|
+
if (typeof valor !== "string")
|
|
36
|
+
throw new Error(`Jira contestó algo que no se entiende (${tool})`);
|
|
37
|
+
return valor;
|
|
38
|
+
}
|
|
39
|
+
function lista(tool, valor) {
|
|
40
|
+
if (!Array.isArray(valor))
|
|
41
|
+
throw new Error(`Jira contestó algo que no se entiende (${tool})`);
|
|
42
|
+
return valor;
|
|
43
|
+
}
|
|
44
|
+
/** Solo el `displayName`: `emailAddress` y `accountId` del `assignee` NUNCA salen de aquí. */
|
|
45
|
+
function nombreDelAsignado(valor) {
|
|
46
|
+
if (typeof valor !== "object" || valor === null)
|
|
47
|
+
return undefined;
|
|
48
|
+
const d = valor.displayName;
|
|
49
|
+
return typeof d === "string" ? d : undefined;
|
|
50
|
+
}
|
|
51
|
+
function tareaDesdeIssue(tool, issue, urlDelSitio) {
|
|
52
|
+
const clave = texto(tool, issue.key);
|
|
53
|
+
const fields = objeto(tool, issue.fields);
|
|
54
|
+
const status = objeto(tool, fields.status);
|
|
55
|
+
const statusCategory = typeof status.statusCategory === "object" && status.statusCategory !== null
|
|
56
|
+
? status.statusCategory
|
|
57
|
+
: undefined;
|
|
58
|
+
const asignado = nombreDelAsignado(fields.assignee);
|
|
59
|
+
return {
|
|
60
|
+
clave,
|
|
61
|
+
titulo: texto(tool, fields.summary),
|
|
62
|
+
estado: texto(tool, status.name),
|
|
63
|
+
categoria: categoriaDeEstado(typeof statusCategory?.key === "string" ? statusCategory.key : undefined),
|
|
64
|
+
...(asignado !== undefined ? { asignado } : {}),
|
|
65
|
+
...(urlDelSitio !== undefined ? { url: `${urlDelSitio}/browse/${clave}` } : {}),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* `crearGestorJira`: cada instancia cachea la url pública de cada `sitio` (`cloudId`) que
|
|
70
|
+
* `sitios()` haya devuelto, para poder componer `url = <url del sitio>/browse/<clave>` sin
|
|
71
|
+
* volver a preguntar. Un sitio nunca visto por esta instancia deja `url` AUSENTE — no se
|
|
72
|
+
* inventa una URL a partir del `cloudId`.
|
|
73
|
+
*/
|
|
74
|
+
/** El máximo que admite `getVisibleJiraProjects` por llamada (medido en su esquema). */
|
|
75
|
+
export const PROYECTOS_POR_PAGINA = 50;
|
|
76
|
+
/**
|
|
77
|
+
* Cuántas pendientes se piden de una vez: el máximo que admite `searchJiraIssuesUsingJql`. El panel
|
|
78
|
+
* FILTRA por estado y CUENTA en el cliente sobre esta lista, así que cuanto más entera llegue,
|
|
79
|
+
* menos mienten los números de las pastillas.
|
|
80
|
+
*/
|
|
81
|
+
export const PENDIENTES_POR_CONSULTA = 100;
|
|
82
|
+
/** Cuántas páginas de proyectos se piden como mucho: 1000 proyectos. */
|
|
83
|
+
const TOPE_DE_PAGINAS_DE_PROYECTOS = 20;
|
|
84
|
+
export function crearGestorJira(llamar) {
|
|
85
|
+
const urlPorSitio = new Map();
|
|
86
|
+
async function sitios() {
|
|
87
|
+
const cuerpo = json("getAccessibleAtlassianResources", await llamar("getAccessibleAtlassianResources", {}));
|
|
88
|
+
return lista("getAccessibleAtlassianResources", cuerpo).map((f) => {
|
|
89
|
+
const x = objeto("getAccessibleAtlassianResources", f);
|
|
90
|
+
const id = texto("getAccessibleAtlassianResources", x.id);
|
|
91
|
+
const url = texto("getAccessibleAtlassianResources", x.url);
|
|
92
|
+
urlPorSitio.set(id, url);
|
|
93
|
+
return { id, nombre: texto("getAccessibleAtlassianResources", x.name), url };
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Los proyectos visibles, por PÁGINAS: la tool admite como mucho `PROYECTOS_POR_PAGINA` por
|
|
98
|
+
* llamada (su esquema declara `maximum: 50` y rechaza más con un -32602; se pidió 100 y el panel
|
|
99
|
+
* enseñó el error) y pagina con `startAt`. Se sigue hasta `isLast` o una página vacía, con un
|
|
100
|
+
* tope de páginas para que una respuesta que nunca diga `isLast` no deje el bucle abierto.
|
|
101
|
+
*/
|
|
102
|
+
async function proyectos(sitio) {
|
|
103
|
+
const salida = [];
|
|
104
|
+
for (let pagina = 0; pagina < TOPE_DE_PAGINAS_DE_PROYECTOS; pagina++) {
|
|
105
|
+
const cuerpo = objeto("getVisibleJiraProjects", json("getVisibleJiraProjects", await llamar("getVisibleJiraProjects", { cloudId: sitio, maxResults: PROYECTOS_POR_PAGINA, startAt: salida.length })));
|
|
106
|
+
const valores = lista("getVisibleJiraProjects", cuerpo.values);
|
|
107
|
+
for (const v of valores) {
|
|
108
|
+
const x = objeto("getVisibleJiraProjects", v);
|
|
109
|
+
salida.push({ clave: texto("getVisibleJiraProjects", x.key), nombre: texto("getVisibleJiraProjects", x.name) });
|
|
110
|
+
}
|
|
111
|
+
if (valores.length === 0 || cuerpo.isLast !== false)
|
|
112
|
+
break;
|
|
113
|
+
}
|
|
114
|
+
return salida;
|
|
115
|
+
}
|
|
116
|
+
async function pendientes(v, filtro, opciones) {
|
|
117
|
+
const motivo = motivoDeClaveDeProyecto(v.proyecto);
|
|
118
|
+
if (motivo !== undefined)
|
|
119
|
+
throw new Error(motivo);
|
|
120
|
+
const cuerpo = objeto("searchJiraIssuesUsingJql", json("searchJiraIssuesUsingJql", await llamar("searchJiraIssuesUsingJql", {
|
|
121
|
+
cloudId: v.sitio,
|
|
122
|
+
jql: jqlDePendientes(v, filtro, opciones),
|
|
123
|
+
maxResults: PENDIENTES_POR_CONSULTA,
|
|
124
|
+
fields: ["summary", "status", "assignee"],
|
|
125
|
+
})));
|
|
126
|
+
const urlDelSitio = urlPorSitio.get(v.sitio);
|
|
127
|
+
return lista("searchJiraIssuesUsingJql", cuerpo.issues).map((i) => tareaDesdeIssue("searchJiraIssuesUsingJql", objeto("searchJiraIssuesUsingJql", i), urlDelSitio));
|
|
128
|
+
}
|
|
129
|
+
async function ficha(v, clave) {
|
|
130
|
+
const cuerpo = objeto("getJiraIssue", json("getJiraIssue", await llamar("getJiraIssue", { cloudId: v.sitio, issueIdOrKey: clave, fields: ["summary", "status", "assignee", "description"] })));
|
|
131
|
+
const urlDelSitio = urlPorSitio.get(v.sitio);
|
|
132
|
+
const fields = objeto("getJiraIssue", cuerpo.fields);
|
|
133
|
+
return {
|
|
134
|
+
...tareaDesdeIssue("getJiraIssue", cuerpo, urlDelSitio),
|
|
135
|
+
descripcion: typeof fields.description === "string" ? fields.description : "",
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
async function transiciones(v, clave) {
|
|
139
|
+
const cuerpo = objeto("getTransitionsForJiraIssue", json("getTransitionsForJiraIssue", await llamar("getTransitionsForJiraIssue", { cloudId: v.sitio, issueIdOrKey: clave })));
|
|
140
|
+
return lista("getTransitionsForJiraIssue", cuerpo.transitions)
|
|
141
|
+
.map((t) => objeto("getTransitionsForJiraIssue", t))
|
|
142
|
+
.filter((t) => t.isAvailable !== false)
|
|
143
|
+
.map((t) => {
|
|
144
|
+
const destino = objeto("getTransitionsForJiraIssue", t.to);
|
|
145
|
+
const statusCategory = typeof destino.statusCategory === "object" && destino.statusCategory !== null
|
|
146
|
+
? destino.statusCategory
|
|
147
|
+
: undefined;
|
|
148
|
+
return {
|
|
149
|
+
id: texto("getTransitionsForJiraIssue", t.id),
|
|
150
|
+
nombre: texto("getTransitionsForJiraIssue", t.name),
|
|
151
|
+
destino: texto("getTransitionsForJiraIssue", destino.name),
|
|
152
|
+
categoria: categoriaDeEstado(typeof statusCategory?.key === "string" ? statusCategory.key : undefined),
|
|
153
|
+
};
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
async function transicionar(v, clave, transicion) {
|
|
157
|
+
await llamar("transitionJiraIssue", { cloudId: v.sitio, issueIdOrKey: clave, transition: { id: transicion } });
|
|
158
|
+
}
|
|
159
|
+
async function comentar(v, clave, cuerpo) {
|
|
160
|
+
await llamar("addCommentToJiraIssue", { cloudId: v.sitio, issueIdOrKey: clave, commentBody: cuerpo, contentFormat: "markdown" });
|
|
161
|
+
}
|
|
162
|
+
return { sitios, proyectos, pendientes, ficha, transiciones, transicionar, comentar };
|
|
163
|
+
}
|
|
164
|
+
//# sourceMappingURL=gestorJira.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gestorJira.js","sourceRoot":"","sources":["../../../src/agent/conectores/gestorJira.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* El adaptador de Notion sobre `GestorDeTareasPort` (`core/gestorDeTareas.ts`, IXCODE-15): el
|
|
3
|
+
* ÚNICO fichero que conoce los nombres de las tools de Notion y la forma de sus respuestas — el
|
|
4
|
+
* molde es `gestorJira.ts`, y nada fuera de aquí sabe que el gestor de tareas es Notion.
|
|
5
|
+
*
|
|
6
|
+
* El «proyecto» es un DATA SOURCE de una base de Notion (`collection://…`): se busca la base por
|
|
7
|
+
* texto (`notion-search`), se resuelve su data source al ELEGIRLA (`notion-fetch`), y de su
|
|
8
|
+
* esquema se entiende qué propiedad es el estado (tipo `status`, con sus grupos `to_do`/
|
|
9
|
+
* `in_progress`/`complete`), cuál el título y cuál el asignado (la primera `person`). Las
|
|
10
|
+
* pendientes salen de un SQL de solo lectura con `params` (`sqlDePendientes`, puro).
|
|
11
|
+
*
|
|
12
|
+
* Todas las respuestas son `{content:[{type:"text", text:"<JSON>"}]}` (medido, 29-09-2026); el
|
|
13
|
+
* JSON de `notion-fetch` lleva además un `text` con marcado propio (`<data-source-state>`,
|
|
14
|
+
* `<properties>`, `<content>`) del que se sacan las piezas por patrón. Lectura DEFENSIVA, como en
|
|
15
|
+
* Jira: una respuesta que no se entiende LANZA, nunca vuelve como lista vacía.
|
|
16
|
+
*
|
|
17
|
+
* Del asignado solo cruza el NOMBRE: `notion-get-users` trae el correo, y de aquí no sale. Un id
|
|
18
|
+
* que no se resuelve (medido: los asignados de una plantilla no son miembros del espacio) deja el
|
|
19
|
+
* asignado AUSENTE — no se inventa ni se enseña el id.
|
|
20
|
+
*/
|
|
21
|
+
import { categoriaDeGrupoDeNotion, etiquetaDeClave, motivoDeFuenteDeNotion, motivoDeReferenciaDeNotion, SITIO_DE_NOTION, sqlDePendientes, } from "../../core/gestorDeTareas.js";
|
|
22
|
+
const noSeEntiende = (tool) => new Error(`Notion contestó algo que no se entiende (${tool})`);
|
|
23
|
+
function json(tool, texto) {
|
|
24
|
+
try {
|
|
25
|
+
return JSON.parse(texto);
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
throw noSeEntiende(tool);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
function objeto(tool, valor) {
|
|
32
|
+
if (typeof valor !== "object" || valor === null || Array.isArray(valor))
|
|
33
|
+
throw noSeEntiende(tool);
|
|
34
|
+
return valor;
|
|
35
|
+
}
|
|
36
|
+
function texto(tool, valor) {
|
|
37
|
+
if (typeof valor !== "string")
|
|
38
|
+
throw noSeEntiende(tool);
|
|
39
|
+
return valor;
|
|
40
|
+
}
|
|
41
|
+
function lista(tool, valor) {
|
|
42
|
+
if (!Array.isArray(valor))
|
|
43
|
+
throw noSeEntiende(tool);
|
|
44
|
+
return valor;
|
|
45
|
+
}
|
|
46
|
+
/** Un id de página: UUID con o sin guiones. Entra en un `notion-fetch` y en una escritura. */
|
|
47
|
+
function motivoDeClaveDeNotion(clave) {
|
|
48
|
+
return /^[0-9a-f]{8}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{4}-?[0-9a-f]{12}$/.test(clave) ? undefined : `«${clave}» no es una página de Notion`;
|
|
49
|
+
}
|
|
50
|
+
/** Lo que se enseña de una página: sus 8 primeros caracteres de id (el UUID entero no se lee). */
|
|
51
|
+
function etiquetaDe(clave) {
|
|
52
|
+
return etiquetaDeClave(clave) ?? clave;
|
|
53
|
+
}
|
|
54
|
+
/** El orden en que se enseñan los grupos de estado: el de un tablero, de lo por hacer a lo terminado. */
|
|
55
|
+
const ORDEN_DE_GRUPOS = ["to_do", "current", "future", "in_progress", "complete"];
|
|
56
|
+
/** Los ids `user://…` de un valor de persona, venga como JSON de la fila SQL o como `<mention-user>` de la ficha. */
|
|
57
|
+
function idsDeUsuarios(valor) {
|
|
58
|
+
const t = typeof valor === "string" ? valor : JSON.stringify(valor ?? null);
|
|
59
|
+
return [...t.matchAll(/user:\/\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})/g)].map((m) => m[1]);
|
|
60
|
+
}
|
|
61
|
+
/** Cuánto de la página entra como descripción: una ficha no es la página entera. */
|
|
62
|
+
export const TOPE_DE_DESCRIPCION = 8000;
|
|
63
|
+
/** Cuántas páginas de usuarios se piden como mucho (de 100 en 100, el máximo de su esquema). */
|
|
64
|
+
const TOPE_DE_PAGINAS_DE_USUARIOS = 5;
|
|
65
|
+
/** Cuántas bases se piden a `notion-search` de una vez: el máximo de su esquema (medido). */
|
|
66
|
+
export const BASES_POR_BUSQUEDA = 50;
|
|
67
|
+
/**
|
|
68
|
+
* El esquema de un `notion-fetch` de una base o de un data source: el PRIMER `<data-source-state>`
|
|
69
|
+
* (una base puede tener varios, y se dice cuántos), o el motivo de por qué esa base no vale.
|
|
70
|
+
*/
|
|
71
|
+
export function esquemaDeFetch(tool, cuerpoTexto) {
|
|
72
|
+
const bloques = [...cuerpoTexto.matchAll(/<data-source-state>\s*([\s\S]*?)\s*<\/data-source-state>/g)].map((m) => m[1]);
|
|
73
|
+
// Medido: la base «My Tasks» de Notion es una vista sin data source propio (`dataSourceUrl: ""`),
|
|
74
|
+
// y su fetch no trae ningún `<data-source-state>`. Es una base que no vale, no una respuesta rota.
|
|
75
|
+
if (bloques.length === 0 && /<database[\s>]/.test(cuerpoTexto))
|
|
76
|
+
return { motivo: "esta base no tiene un data source propio (es una vista)" };
|
|
77
|
+
if (bloques.length === 0)
|
|
78
|
+
throw noSeEntiende(tool);
|
|
79
|
+
const estado = objeto(tool, json(tool, bloques[0]));
|
|
80
|
+
const proyecto = texto(tool, estado.url);
|
|
81
|
+
if (motivoDeFuenteDeNotion(proyecto) !== undefined)
|
|
82
|
+
throw noSeEntiende(tool);
|
|
83
|
+
const nombre = typeof estado.name === "string" && estado.name.trim() !== "" ? estado.name : "Sin título";
|
|
84
|
+
const propiedades = Object.values(objeto(tool, estado.schema)).map((p) => objeto(tool, p));
|
|
85
|
+
const deTipo = (tipo) => propiedades.find((p) => p.type === tipo && typeof p.name === "string");
|
|
86
|
+
const status = deTipo("status");
|
|
87
|
+
if (status === undefined)
|
|
88
|
+
return { motivo: "esta base no tiene una propiedad de estado" };
|
|
89
|
+
const titulo = deTipo("title");
|
|
90
|
+
if (titulo === undefined)
|
|
91
|
+
return { motivo: "esta base no tiene una propiedad de título" };
|
|
92
|
+
const persona = deTipo("person");
|
|
93
|
+
const grupos = objeto(tool, status.groups);
|
|
94
|
+
const claves = [...ORDEN_DE_GRUPOS.filter((g) => g in grupos), ...Object.keys(grupos).filter((g) => !ORDEN_DE_GRUPOS.includes(g))];
|
|
95
|
+
const opciones = claves.flatMap((g) => lista(tool, grupos[g]).map((o) => ({ nombre: texto(tool, objeto(tool, o).name), categoria: categoriaDeGrupoDeNotion(g) })));
|
|
96
|
+
if (opciones.length === 0)
|
|
97
|
+
return { motivo: "la propiedad de estado no tiene opciones" };
|
|
98
|
+
const esquema = {
|
|
99
|
+
proyecto,
|
|
100
|
+
nombre,
|
|
101
|
+
estado: { propiedad: status.name, opciones },
|
|
102
|
+
titulo: titulo.name,
|
|
103
|
+
...(persona === undefined ? {} : { asignado: persona.name }),
|
|
104
|
+
...(bloques.length > 1 ? { fuentes: bloques.length } : {}),
|
|
105
|
+
};
|
|
106
|
+
return { esquema };
|
|
107
|
+
}
|
|
108
|
+
/** La descripción de una página: lo de dentro de `<content>`, sin los bloques vacíos. Una página en blanco es `""`. */
|
|
109
|
+
export function descripcionDePagina(cuerpoTexto) {
|
|
110
|
+
const m = /<content>\s*([\s\S]*?)\s*<\/content>/.exec(cuerpoTexto);
|
|
111
|
+
if (m === null)
|
|
112
|
+
return "";
|
|
113
|
+
const limpio = m[1].split("\n").filter((l) => l.trim() !== "<empty-block/>").join("\n").trim();
|
|
114
|
+
return limpio.length > TOPE_DE_DESCRIPCION ? `${limpio.slice(0, TOPE_DE_DESCRIPCION)}…` : limpio;
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* El comentario de cierre tal como Notion lo enseña BIEN (IXCODE-15). El esquema de
|
|
118
|
+
* `notion-create-comment` dice que los encabezados, las listas, las tablas, las citas y los bloques
|
|
119
|
+
* de código se guardan como TEXTO —saldrían `## Qué cambió` y `- a` literales—, y que lo de dentro
|
|
120
|
+
* de la línea (negrita, cursiva, código, enlaces) sí se pinta. Así que solo se cambian los
|
|
121
|
+
* MARCADORES de bloque: `## Título` → `Título:` en su línea y `- x`/`* x`/`+ x` → `• x`; nada
|
|
122
|
+
* más (un bloque de código, que `comentarioDeCierre` no produce, se queda como está). Mismas líneas, mismo orden, mismo texto: lo que la persona
|
|
123
|
+
* aprobó no cambia de sentido. `**x**` y `` `x` `` se quedan porque Notion los pinta.
|
|
124
|
+
*/
|
|
125
|
+
export function comentarioParaNotion(markdown) {
|
|
126
|
+
return markdown
|
|
127
|
+
.split("\n")
|
|
128
|
+
.map((linea) => {
|
|
129
|
+
const titulo = /^\s{0,3}#{1,6}\s+(.*?)\s*#*\s*$/.exec(linea);
|
|
130
|
+
if (titulo !== null) {
|
|
131
|
+
const t = titulo[1];
|
|
132
|
+
return t.endsWith(":") ? t : `${t}:`;
|
|
133
|
+
}
|
|
134
|
+
const punto = /^(\s*)[-*+]\s+(.*)$/.exec(linea);
|
|
135
|
+
if (punto !== null)
|
|
136
|
+
return `${punto[1]}• ${punto[2]}`;
|
|
137
|
+
return linea;
|
|
138
|
+
})
|
|
139
|
+
.join("\n");
|
|
140
|
+
}
|
|
141
|
+
export function crearGestorNotion(llamar) {
|
|
142
|
+
/**
|
|
143
|
+
* El esquema de cada data source ya entendido. `describirProyecto` lo pide SIEMPRE de nuevo (es
|
|
144
|
+
* la pregunta explícita de la persona) y refresca esto; las demás lo usan si está. Un SQL que
|
|
145
|
+
* falla lo TIRA: una propiedad renombrada en Notion no puede dejar el panel roto hasta reiniciar.
|
|
146
|
+
*/
|
|
147
|
+
const esquemas = new Map();
|
|
148
|
+
/** El data source al que pertenece cada página vista (su `<parent-data-source>`). */
|
|
149
|
+
const fuenteDePagina = new Map();
|
|
150
|
+
let nombres;
|
|
151
|
+
let yo;
|
|
152
|
+
async function describir(ref) {
|
|
153
|
+
const motivo = motivoDeReferenciaDeNotion(ref);
|
|
154
|
+
if (motivo !== undefined)
|
|
155
|
+
throw new Error(motivo);
|
|
156
|
+
const cuerpo = objeto("notion-fetch", json("notion-fetch", await llamar("notion-fetch", { id: ref })));
|
|
157
|
+
const tipo = objeto("notion-fetch", cuerpo.metadata).type;
|
|
158
|
+
if (tipo !== "database" && tipo !== "data_source")
|
|
159
|
+
return { motivo: "eso no es una base de datos de Notion" };
|
|
160
|
+
const d = esquemaDeFetch("notion-fetch", texto("notion-fetch", cuerpo.text));
|
|
161
|
+
if ("esquema" in d) {
|
|
162
|
+
// Pedir un data source y que conteste OTRO no es lo pedido: mejor no entenderlo que vincular algo distinto.
|
|
163
|
+
if (ref.startsWith("collection://") && d.esquema.proyecto !== ref)
|
|
164
|
+
throw noSeEntiende("notion-fetch");
|
|
165
|
+
esquemas.set(d.esquema.proyecto, d.esquema);
|
|
166
|
+
}
|
|
167
|
+
return d;
|
|
168
|
+
}
|
|
169
|
+
async function esquemaDe(fuente) {
|
|
170
|
+
const motivo = motivoDeFuenteDeNotion(fuente);
|
|
171
|
+
if (motivo !== undefined)
|
|
172
|
+
throw new Error(motivo);
|
|
173
|
+
const cacheado = esquemas.get(fuente);
|
|
174
|
+
if (cacheado !== undefined)
|
|
175
|
+
return cacheado;
|
|
176
|
+
const d = await describir(fuente);
|
|
177
|
+
if ("motivo" in d)
|
|
178
|
+
throw new Error(d.motivo);
|
|
179
|
+
return d.esquema;
|
|
180
|
+
}
|
|
181
|
+
/** Quien tiene la sesión del conector (`user_id: "self"`, medido). Se pregunta una vez por instancia. */
|
|
182
|
+
async function yoMismo() {
|
|
183
|
+
if (yo !== undefined)
|
|
184
|
+
return yo;
|
|
185
|
+
const cuerpo = objeto("notion-get-users", json("notion-get-users", await llamar("notion-get-users", { user_id: "self" })));
|
|
186
|
+
const primero = lista("notion-get-users", cuerpo.results)[0];
|
|
187
|
+
if (primero === undefined)
|
|
188
|
+
throw new Error("Notion no dice quién tiene la sesión");
|
|
189
|
+
yo = texto("notion-get-users", objeto("notion-get-users", primero).id);
|
|
190
|
+
return yo;
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* id → nombre de los miembros del espacio, paginado y cacheado por instancia. Solo el NOMBRE:
|
|
194
|
+
* el `email` de cada miembro no sale de esta función. Un fallo NO tumba la lista de tareas: sin
|
|
195
|
+
* nombres, los asignados salen ausentes, y se vuelve a intentar en la siguiente.
|
|
196
|
+
*/
|
|
197
|
+
async function nombresDeUsuarios() {
|
|
198
|
+
if (nombres !== undefined)
|
|
199
|
+
return nombres;
|
|
200
|
+
try {
|
|
201
|
+
const mapa = new Map();
|
|
202
|
+
let cursor;
|
|
203
|
+
for (let pagina = 0; pagina < TOPE_DE_PAGINAS_DE_USUARIOS; pagina++) {
|
|
204
|
+
const cuerpo = objeto("notion-get-users", json("notion-get-users", await llamar("notion-get-users", { page_size: 100, ...(cursor === undefined ? {} : { start_cursor: cursor }) })));
|
|
205
|
+
for (const u of lista("notion-get-users", cuerpo.results)) {
|
|
206
|
+
const x = objeto("notion-get-users", u);
|
|
207
|
+
if (typeof x.id === "string" && typeof x.name === "string" && x.name.trim() !== "")
|
|
208
|
+
mapa.set(x.id, x.name);
|
|
209
|
+
}
|
|
210
|
+
if (cuerpo.has_more !== true || typeof cuerpo.next_cursor !== "string")
|
|
211
|
+
break;
|
|
212
|
+
cursor = cuerpo.next_cursor;
|
|
213
|
+
}
|
|
214
|
+
nombres = mapa;
|
|
215
|
+
return mapa;
|
|
216
|
+
}
|
|
217
|
+
catch {
|
|
218
|
+
return new Map();
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
async function asignadoDe(valor) {
|
|
222
|
+
const ids = idsDeUsuarios(valor);
|
|
223
|
+
if (ids.length === 0)
|
|
224
|
+
return undefined;
|
|
225
|
+
const mapa = await nombresDeUsuarios();
|
|
226
|
+
const resueltos = ids.flatMap((id) => (mapa.has(id) ? [mapa.get(id)] : []));
|
|
227
|
+
return resueltos.length === 0 ? undefined : resueltos.join(", ");
|
|
228
|
+
}
|
|
229
|
+
function estadoYCategoria(esquema, valor) {
|
|
230
|
+
if (typeof valor !== "string" || valor === "")
|
|
231
|
+
return { estado: "Sin estado", categoria: "por-hacer" };
|
|
232
|
+
return { estado: valor, categoria: esquema.estado.opciones.find((o) => o.nombre === valor)?.categoria ?? "por-hacer" };
|
|
233
|
+
}
|
|
234
|
+
/** La página: su JSON, su data source padre (si lo dice) y sus propiedades. */
|
|
235
|
+
async function pagina(clave) {
|
|
236
|
+
const motivo = motivoDeClaveDeNotion(clave);
|
|
237
|
+
if (motivo !== undefined)
|
|
238
|
+
throw new Error(motivo);
|
|
239
|
+
const cuerpo = objeto("notion-fetch", json("notion-fetch", await llamar("notion-fetch", { id: clave })));
|
|
240
|
+
if (objeto("notion-fetch", cuerpo.metadata).type !== "page")
|
|
241
|
+
throw new Error("eso no es una página de Notion");
|
|
242
|
+
const t = texto("notion-fetch", cuerpo.text);
|
|
243
|
+
const padre = /<parent-data-source url="(collection:\/\/[0-9a-f-]{36})"/.exec(t)?.[1];
|
|
244
|
+
if (padre !== undefined)
|
|
245
|
+
fuenteDePagina.set(clave, padre);
|
|
246
|
+
const props = /<properties>\s*([\s\S]*?)\s*<\/properties>/.exec(t);
|
|
247
|
+
const propiedades = props === null ? {} : objeto("notion-fetch", json("notion-fetch", props[1]));
|
|
248
|
+
return { cuerpo, texto: t, ...(padre === undefined ? {} : { fuente: padre }), propiedades };
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* El data source de una página, para transicionar y cerrar: el de la PROPIA página, no el del
|
|
252
|
+
* vínculo de ahora — una sesión puede cerrarse con el proyecto ya vinculado a otra base (o a
|
|
253
|
+
* Jira, o a nada: `proyecto: ""`). Solo si la página no lo dice se usa el del vínculo.
|
|
254
|
+
*/
|
|
255
|
+
async function fuenteParaPagina(v, clave) {
|
|
256
|
+
const vista = fuenteDePagina.get(clave);
|
|
257
|
+
if (vista !== undefined)
|
|
258
|
+
return vista;
|
|
259
|
+
const p = await pagina(clave);
|
|
260
|
+
if (p.fuente !== undefined)
|
|
261
|
+
return p.fuente;
|
|
262
|
+
if (motivoDeFuenteDeNotion(v.proyecto) === undefined)
|
|
263
|
+
return v.proyecto;
|
|
264
|
+
throw new Error("esa página no pertenece a ninguna base de Notion");
|
|
265
|
+
}
|
|
266
|
+
async function sitios() {
|
|
267
|
+
// Local: un espacio por cuenta OAuth, y el MCP no expone su nombre (medido). `asegurarSitios`
|
|
268
|
+
// del servidor lo llama antes de cada lista: aquí no cuesta una llamada.
|
|
269
|
+
return [{ id: SITIO_DE_NOTION, nombre: "Notion" }];
|
|
270
|
+
}
|
|
271
|
+
async function proyectos() {
|
|
272
|
+
// Una lista vacía diría «no tienes bases»: no es verdad, es que en Notion se BUSCAN.
|
|
273
|
+
throw new Error("en Notion las bases se buscan por nombre");
|
|
274
|
+
}
|
|
275
|
+
async function buscarProyectos(filtro) {
|
|
276
|
+
const q = filtro.trim();
|
|
277
|
+
if (q === "")
|
|
278
|
+
throw new Error("escribe algo para buscar la base");
|
|
279
|
+
const cuerpo = objeto("notion-search", json("notion-search", await llamar("notion-search", { query: q, query_type: "internal", page_size: BASES_POR_BUSQUEDA, max_highlight_length: 0 })));
|
|
280
|
+
return lista("notion-search", cuerpo.results)
|
|
281
|
+
.map((r) => objeto("notion-search", r))
|
|
282
|
+
.filter((r) => r.type === "database")
|
|
283
|
+
.map((r) => {
|
|
284
|
+
const titulo = typeof r.title === "string" && r.title.trim() !== "" ? r.title : "Sin título";
|
|
285
|
+
return {
|
|
286
|
+
proyecto: texto("notion-search", r.id),
|
|
287
|
+
nombre: titulo,
|
|
288
|
+
...(typeof r.path === "string" && r.path.trim() !== "" ? { ruta: r.path } : {}),
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
async function describirProyecto(v) {
|
|
293
|
+
return describir(v.proyecto);
|
|
294
|
+
}
|
|
295
|
+
async function pendientes(v, filtro, opciones) {
|
|
296
|
+
const esquema = await esquemaDe(v.proyecto);
|
|
297
|
+
if (opciones?.mias === true && esquema.asignado === undefined)
|
|
298
|
+
throw new Error("esta base no tiene una propiedad de persona");
|
|
299
|
+
const { query, params } = sqlDePendientes(esquema, filtro, opciones?.mias === true ? { yo: await yoMismo() } : {});
|
|
300
|
+
let respuesta;
|
|
301
|
+
try {
|
|
302
|
+
respuesta = await llamar("notion-query-data-sources", { data: { data_source_urls: [esquema.proyecto], query, params } });
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
esquemas.delete(esquema.proyecto);
|
|
306
|
+
throw error;
|
|
307
|
+
}
|
|
308
|
+
const cuerpo = objeto("notion-query-data-sources", json("notion-query-data-sources", respuesta));
|
|
309
|
+
const filas = lista("notion-query-data-sources", cuerpo.results).map((f) => objeto("notion-query-data-sources", f));
|
|
310
|
+
const salida = [];
|
|
311
|
+
for (const f of filas) {
|
|
312
|
+
const clave = texto("notion-query-data-sources", f.id);
|
|
313
|
+
const titulo = f[esquema.titulo];
|
|
314
|
+
const asignado = esquema.asignado === undefined ? undefined : await asignadoDe(f[esquema.asignado]);
|
|
315
|
+
salida.push({
|
|
316
|
+
clave,
|
|
317
|
+
etiqueta: etiquetaDe(clave),
|
|
318
|
+
titulo: typeof titulo === "string" && titulo.trim() !== "" ? titulo : "Sin título",
|
|
319
|
+
...estadoYCategoria(esquema, f[esquema.estado.propiedad]),
|
|
320
|
+
...(asignado === undefined ? {} : { asignado }),
|
|
321
|
+
...(typeof f.url === "string" ? { url: f.url } : {}),
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
return salida;
|
|
325
|
+
}
|
|
326
|
+
async function ficha(v, clave) {
|
|
327
|
+
const p = await pagina(clave);
|
|
328
|
+
// La ficha es la de una tarea del proyecto VINCULADO: una página de otra base no se abre como si lo fuera.
|
|
329
|
+
if (p.fuente !== undefined && motivoDeFuenteDeNotion(v.proyecto) === undefined && p.fuente !== v.proyecto) {
|
|
330
|
+
throw new Error("esa página no es de la base vinculada");
|
|
331
|
+
}
|
|
332
|
+
const esquema = await esquemaDe(p.fuente ?? v.proyecto);
|
|
333
|
+
const titulo = p.propiedades[esquema.titulo] ?? p.cuerpo.title;
|
|
334
|
+
const asignado = esquema.asignado === undefined ? undefined : await asignadoDe(p.propiedades[esquema.asignado]);
|
|
335
|
+
return {
|
|
336
|
+
clave,
|
|
337
|
+
etiqueta: etiquetaDe(clave),
|
|
338
|
+
titulo: typeof titulo === "string" && titulo.trim() !== "" ? titulo : "Sin título",
|
|
339
|
+
...estadoYCategoria(esquema, p.propiedades[esquema.estado.propiedad]),
|
|
340
|
+
...(asignado === undefined ? {} : { asignado }),
|
|
341
|
+
...(typeof p.cuerpo.url === "string" ? { url: p.cuerpo.url } : {}),
|
|
342
|
+
descripcion: descripcionDePagina(p.texto),
|
|
343
|
+
};
|
|
344
|
+
}
|
|
345
|
+
/** En Notion no hay transiciones: cada OPCIÓN del estado es un destino, y su nombre es el id. */
|
|
346
|
+
async function transiciones(v, clave) {
|
|
347
|
+
const esquema = await esquemaDe(await fuenteParaPagina(v, clave));
|
|
348
|
+
return esquema.estado.opciones.map((o) => ({ id: o.nombre, nombre: o.nombre, destino: o.nombre, categoria: o.categoria }));
|
|
349
|
+
}
|
|
350
|
+
async function transicionar(v, clave, transicion) {
|
|
351
|
+
const esquema = await esquemaDe(await fuenteParaPagina(v, clave));
|
|
352
|
+
// Solo una opción que la base TIENE: un nombre cualquiera crearía (o fallaría) en silencio.
|
|
353
|
+
if (!esquema.estado.opciones.some((o) => o.nombre === transicion))
|
|
354
|
+
throw new Error(`«${transicion}» no es un estado de esa base`);
|
|
355
|
+
await llamar("notion-update-page", { page_id: clave, command: "update_properties", properties: { [esquema.estado.propiedad]: transicion } });
|
|
356
|
+
}
|
|
357
|
+
async function comentar(_v, clave, cuerpo) {
|
|
358
|
+
const motivo = motivoDeClaveDeNotion(clave);
|
|
359
|
+
if (motivo !== undefined)
|
|
360
|
+
throw new Error(motivo);
|
|
361
|
+
await llamar("notion-create-comment", { page_id: clave, markdown: comentarioParaNotion(cuerpo) });
|
|
362
|
+
}
|
|
363
|
+
return { sitios, proyectos, buscarProyectos, describirProyecto, pendientes, ficha, transiciones, transicionar, comentar };
|
|
364
|
+
}
|
|
365
|
+
//# sourceMappingURL=gestorNotion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gestorNotion.js","sourceRoot":"","sources":["../../../src/agent/conectores/gestorNotion.ts"],"names":[],"mappings":"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"}
|