@ajuarezso/lienzo-mcp 0.3.0 → 0.3.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/README.en.md +95 -10
- package/README.md +95 -10
- package/index.mjs +61 -13
- package/lib/canal.mjs +778 -0
- package/lib/esperar.mjs +8 -3
- package/lib/lienzo.mjs +30 -6
- package/package.json +1 -1
package/lib/esperar.mjs
CHANGED
|
@@ -119,13 +119,18 @@ async function sondear(consultar, o, limite, consultasPrevias) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
-
/**
|
|
122
|
+
/**
|
|
123
|
+
* Respuesta de lienzo_leer / lienzo_esperar que no entregó todo. OJO: el texto también trae lo que escribieron otros
|
|
124
|
+
* (una tarjeta puede decir «Había más de 20 personas»): mejor el `recortado` de formatearLoteDetalle.
|
|
125
|
+
*/
|
|
123
126
|
export const RE_RECORTADA = /Respuesta recortada|Había más de/;
|
|
124
127
|
|
|
125
128
|
/**
|
|
126
129
|
* Tras formatear lo que trajo una espera con timbre: si la respuesta entró entera, lo consultado ya está
|
|
127
130
|
* entregado y la próxima espera no necesita volver a mirar (ahorra una pasada por cada novedad).
|
|
131
|
+
* `recortado`: el booleano de formatearLoteDetalle (o, por compatibilidad, el texto, que se mira con RE_RECORTADA).
|
|
128
132
|
*/
|
|
129
|
-
export function entregado(timbre, r,
|
|
130
|
-
|
|
133
|
+
export function entregado(timbre, r, recortado) {
|
|
134
|
+
const corto = typeof recortado === 'boolean' ? recortado : RE_RECORTADA.test(String(recortado ?? ''));
|
|
135
|
+
if (timbre && r?.modo === 'timbre' && r.version != null && !corto) timbre.visto = r.version;
|
|
131
136
|
}
|
package/lib/lienzo.mjs
CHANGED
|
@@ -183,6 +183,7 @@ export class Lienzo {
|
|
|
183
183
|
this.intervaloEspera = INTERVALO_MS; // lo que lleva creciendo la espera de lienzo_esperar
|
|
184
184
|
this.participantes = new Map();
|
|
185
185
|
this.participantesEn = 0;
|
|
186
|
+
this._ausentes = new Map(); // id → cuándo se confirmó que no está en la sala (no se recarga todo por él cada vez)
|
|
186
187
|
this.tareasPedidas = new Map(); // id → { estado, respuesta, tomadaPor }
|
|
187
188
|
this.tareasCargadas = false;
|
|
188
189
|
this.listas = new Set(); // ids de las listas que pediste (sus puntos llegan agrupados)
|
|
@@ -345,8 +346,19 @@ export class Lienzo {
|
|
|
345
346
|
|
|
346
347
|
async _participante(id) {
|
|
347
348
|
if (!id) return null;
|
|
348
|
-
if (
|
|
349
|
-
|
|
349
|
+
if (this.participantes.has(id)) return this.participantes.get(id);
|
|
350
|
+
// Un id que no está fuerza una recarga (quien entró recién). Pero si ya se confirmó hace poco que no está (alguien
|
|
351
|
+
// que salió, o un paraId inventado), no se vuelve a leer la sala entera (hasta 500) por cada tarjeta que lo nombre.
|
|
352
|
+
const ausente = this._ausentes.get(id);
|
|
353
|
+
if (ausente != null && Date.now() - ausente < RECARGA_PARTICIPANTES_MS) return null;
|
|
354
|
+
await this._cargarParticipantes(true);
|
|
355
|
+
const p = this.participantes.get(id) || null;
|
|
356
|
+
if (p) this._ausentes.delete(id);
|
|
357
|
+
else {
|
|
358
|
+
if (this._ausentes.size >= 500) this._ausentes.clear();
|
|
359
|
+
this._ausentes.set(id, Date.now());
|
|
360
|
+
}
|
|
361
|
+
return p;
|
|
350
362
|
}
|
|
351
363
|
|
|
352
364
|
/** Cuántos participantes de la sala se llaman igual que `id` (1 = nombre único). */
|
|
@@ -483,6 +495,7 @@ export class Lienzo {
|
|
|
483
495
|
this.listas.clear();
|
|
484
496
|
this.participantes.clear();
|
|
485
497
|
this.participantesEn = 0;
|
|
498
|
+
this._ausentes.clear();
|
|
486
499
|
}
|
|
487
500
|
await this._anotarEnIndice(salaId);
|
|
488
501
|
return { salaId, sala, link: this.link(salaId), yo: this.yo };
|
|
@@ -1268,9 +1281,18 @@ export class Lienzo {
|
|
|
1268
1281
|
* (creadaEn, editadaEn y el estado visto de tus tareas) avanzan SOLO hasta lo que se entregó, y un
|
|
1269
1282
|
* bloque (una lista, o lo que nació en el mismo :commit) se entrega entero o no se entrega.
|
|
1270
1283
|
*/
|
|
1271
|
-
async formatearLote(lote,
|
|
1272
|
-
|
|
1273
|
-
|
|
1284
|
+
async formatearLote(lote, o = {}) {
|
|
1285
|
+
return (await this.formatearLoteDetalle(lote, o)).texto;
|
|
1286
|
+
}
|
|
1287
|
+
|
|
1288
|
+
/**
|
|
1289
|
+
* formatearLote con el dato de si quedó algo sin entregar (`recortado`: tope de caracteres o más de
|
|
1290
|
+
* LIMITE_CONSULTA tarjetas), sin tener que buscarlo en el texto (que también trae lo que escribieron otros).
|
|
1291
|
+
* sinPie: sin los párrafos finales («Respuesta recortada…», «Había más de…», «marca: …»), para el canal.
|
|
1292
|
+
*/
|
|
1293
|
+
async formatearLoteDetalle(lote, { codigo = nuevoCodigo(), max = MAX_RESPUESTA, sinPie = false } = {}) {
|
|
1294
|
+
if (lote.una) return { texto: await this._formatearUna(lote.una, { codigo, max, desdeCaracter: lote.desdeCaracter }), recortado: false };
|
|
1295
|
+
if (lote.lista) return { texto: `${aviso(codigo)}\n\n${await this._formatearLista(lote.lista.padre, lote.lista.puntos, { codigo, max })}`, recortado: false };
|
|
1274
1296
|
const { tarjetas = [], editadas = [], cambios = [], soloAjenas = false, lleno = false } = lote;
|
|
1275
1297
|
const nuevas = new Set(tarjetas.map((t) => t.id));
|
|
1276
1298
|
const items = [
|
|
@@ -1310,6 +1332,8 @@ export class Lienzo {
|
|
|
1310
1332
|
if (bloques.editadas.length) partes.push(`Tarjetas editadas (${piezas.editadas}):`, ...bloques.editadas);
|
|
1311
1333
|
if (bloques.tarjetas.length) partes.push(`Tarjetas (${piezas.tarjetas}):`, ...bloques.tarjetas);
|
|
1312
1334
|
if (!entregados && !cortado) partes.push('No hay tarjetas nuevas.');
|
|
1335
|
+
const recortado = cortado || Boolean(lleno);
|
|
1336
|
+
if (sinPie) return { texto: partes.join('\n\n'), recortado };
|
|
1313
1337
|
if (cortado) {
|
|
1314
1338
|
const total = quedan.cambios + quedan.editadas + quedan.tarjetas;
|
|
1315
1339
|
const desglose = [
|
|
@@ -1324,6 +1348,6 @@ export class Lienzo {
|
|
|
1324
1348
|
}
|
|
1325
1349
|
const marca = soloAjenas ? this.marca : (ultimaCreada ?? lote.desde ?? this.marca);
|
|
1326
1350
|
partes.push(`marca: ${marca ?? '(sin marca)'} — pásala como «desde» para pedir solo lo posterior.`);
|
|
1327
|
-
return partes.join('\n\n');
|
|
1351
|
+
return { texto: partes.join('\n\n'), recortado };
|
|
1328
1352
|
}
|
|
1329
1353
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ajuarezso/lienzo-mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.1",
|
|
4
4
|
"description": "Servidor MCP de Lienzo: une tu agente (Claude Code u otro cliente MCP) a una sala compartida con los agentes de otras personas. / MCP server that joins your agent to a room shared with other people's agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mcp",
|