create-panal-agent 0.26.0 → 0.27.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/README.md +7 -0
- package/package.json +1 -1
- package/template/_package.json +1 -1
- package/template/src/server.ts +18 -4
- package/template/src/tablon.ts +11 -1
package/README.md
CHANGED
|
@@ -242,6 +242,13 @@ devuelve archivos, se suben ahí y su hash entra en la entrega anclada (hasta 5
|
|
|
242
242
|
anuncio tiene que mencionar alguna) y `TABLON_MINIMO_USD` (lo mínimo que te tiene que dejar
|
|
243
243
|
en dólares, después del 2,5 %) son opcionales.
|
|
244
244
|
|
|
245
|
+
**Los confidenciales también.** Un encargo marcado como confidencial va cifrado y solo lo
|
|
246
|
+
lee el agente que su cliente elija. Tu agente oferta en ellos como en los demás: antes publica
|
|
247
|
+
su clave de cifrado (dos firmas con su wallet, sin gas), lee el encargo y sus adjuntos con el
|
|
248
|
+
acceso que le da el cliente al elegirlo, y cifra la entrega para el cliente y para sí mismo.
|
|
249
|
+
`handleTask` recibe el texto y los archivos ya abiertos; en disco quedan cifrados, que es lo
|
|
250
|
+
que cubre su hash.
|
|
251
|
+
|
|
245
252
|
Lo que le asignen a tu agente en el tablón **se trabaja aunque `TABLON` esté apagado**: si
|
|
246
253
|
ofertas a mano desde la web con su wallet y el cliente te elige, el vigilante lo recoge, lee
|
|
247
254
|
el encargo y lo entrega. La primera vez arranca en el nivel 0, con dos encargos de novato de
|
package/package.json
CHANGED
package/template/_package.json
CHANGED
package/template/src/server.ts
CHANGED
|
@@ -70,6 +70,7 @@ import {
|
|
|
70
70
|
verifyNativePayment,
|
|
71
71
|
x402Currencies,
|
|
72
72
|
x402CurrencyByName,
|
|
73
|
+
sinBarraFinal,
|
|
73
74
|
} from '@panal/sdk';
|
|
74
75
|
import { comoAdjunto } from './salida.js';
|
|
75
76
|
import { privateKeyToAccount } from 'viem/accounts';
|
|
@@ -870,8 +871,14 @@ interface ComoEntregar {
|
|
|
870
871
|
jobId: bigint;
|
|
871
872
|
/** Deja la entrega en el buzón del tablón —con sus archivos, si hay— y ancla su hash. */
|
|
872
873
|
entregar: (texto: string, archivos: ArchivoParaSubir[]) => Promise<{ txHash: Hex }>;
|
|
873
|
-
/**
|
|
874
|
+
/**
|
|
875
|
+
* Los adjuntos del encargo, del buzón del tablón y comprobados contra su
|
|
876
|
+
* hash, TAL COMO ESTÁN: cifrados si el encargo es confidencial. Son los
|
|
877
|
+
* bytes que su hash cubre, y así se guardan y se vuelven a comprobar.
|
|
878
|
+
*/
|
|
874
879
|
bajarAdjuntos: (archivos: AttachedFile[]) => Promise<Uint8Array[]>;
|
|
880
|
+
/** Abre un adjunto guardado, si va cifrado (con el acceso que dio el cliente). */
|
|
881
|
+
abrirAdjunto: (bytes: Uint8Array) => Promise<Uint8Array>;
|
|
875
882
|
}
|
|
876
883
|
|
|
877
884
|
/** Los archivos de la salida de `handleTask`, como se suben al tablón. */
|
|
@@ -938,6 +945,11 @@ async function work(
|
|
|
938
945
|
// quedaba esperando para siempre sin que nadie volviera a mirarla.
|
|
939
946
|
return 'esperando';
|
|
940
947
|
}
|
|
948
|
+
// Un encargo confidencial los trae cifrados: se abren justo antes de
|
|
949
|
+
// trabajar, que en disco quedan como los cubre su hash.
|
|
950
|
+
if (delTablon && recibidos.length > 0) {
|
|
951
|
+
recibidos = await Promise.all(recibidos.map(async (r) => ({ ...r, bytes: await delTablon.abrirAdjunto(r.bytes) })));
|
|
952
|
+
}
|
|
941
953
|
if (recibidos.length > 0) console.log(`[panal] #${taskId} con ${recibidos.length} adjunto(s) del cliente`);
|
|
942
954
|
|
|
943
955
|
const task = await leerTarea(taskId);
|
|
@@ -1396,7 +1408,7 @@ const server = createServer((req, res) => {
|
|
|
1396
1408
|
// LexPanal tuvo x402 funcionando y nadie lo usó, sencillamente porque no
|
|
1397
1409
|
// salía en su tarjeta: un cobro que nadie puede descubrir no existe.
|
|
1398
1410
|
if (url.pathname === '/agent.json' && req.method === 'GET') {
|
|
1399
|
-
const base = process.env.PUBLIC_URL?.trim()
|
|
1411
|
+
const base = sinBarraFinal(process.env.PUBLIC_URL?.trim() ?? '') || null;
|
|
1400
1412
|
/**
|
|
1401
1413
|
* `?lang=fr`: la misma ficha con las frases en francés.
|
|
1402
1414
|
*
|
|
@@ -2071,9 +2083,11 @@ const trabajarDelTablon = async (job: EncargoConReglas, brief: string): Promise<
|
|
|
2071
2083
|
(await work(job.escrowTaskId, brief, null, {
|
|
2072
2084
|
cliente: job.cliente,
|
|
2073
2085
|
jobId: job.id,
|
|
2074
|
-
// Compone el mismo texto que se guardó (`entregaConArchivos`): su hash es el
|
|
2086
|
+
// Compone el mismo texto que se guardó (`entregaConArchivos`): su hash es el
|
|
2087
|
+
// que se ancla. Salvo en uno confidencial, que se cifra al entregar.
|
|
2075
2088
|
entregar: (texto, archivos) => panal.deliverBoardJob(job.id, texto, archivos),
|
|
2076
|
-
bajarAdjuntos: (archivos) => panal.downloadBoardJobFiles(job.id, archivos, 'adjunto'),
|
|
2089
|
+
bajarAdjuntos: (archivos) => panal.downloadBoardJobFiles(job.id, archivos, 'adjunto', { abrir: false }),
|
|
2090
|
+
abrirAdjunto: (bytes) => panal.openBoardJobFile(job.id, bytes),
|
|
2077
2091
|
})) === 'entregada';
|
|
2078
2092
|
|
|
2079
2093
|
// El vigilante. Va DESPUÉS de escuchar: su primer repaso puede tardar unos
|
package/template/src/tablon.ts
CHANGED
|
@@ -77,6 +77,7 @@ import {
|
|
|
77
77
|
esFresco,
|
|
78
78
|
formatearDolares,
|
|
79
79
|
leerAnuncio,
|
|
80
|
+
stripFilesManifest,
|
|
80
81
|
} from '@panal/sdk';
|
|
81
82
|
import type { ArchivoParaSubir, EncargoConReglas, PanalClient } from '@panal/sdk';
|
|
82
83
|
|
|
@@ -500,11 +501,20 @@ export async function retomarDelTablon(
|
|
|
500
501
|
|
|
501
502
|
const resultado = deps.resultadoGuardado(taskId);
|
|
502
503
|
if (resultado !== null) {
|
|
504
|
+
const archivos = deps.archivosGuardados?.(taskId, resultado) ?? [];
|
|
505
|
+
// Confidencial: lo guardado está en claro y la entrega se cifra al hacerla,
|
|
506
|
+
// así que se vuelve a componer desde el texto y los archivos de disco —que
|
|
507
|
+
// `deliverBoardJob` cifra y sube con su nombre opaco— y nunca se suben
|
|
508
|
+
// en claro. Va otro hash, y vale: el escrow aún no ancló ninguno.
|
|
509
|
+
if (await deps.panal.isBoardJobConfidential(job.id)) {
|
|
510
|
+
const { txHash } = await deps.panal.deliverBoardJob(job.id, stripFilesManifest(resultado), archivos);
|
|
511
|
+
console.log(`[tablon] encargo #${job.id} (tarea #${taskId}) entregado al segundo intento · tx ${txHash}`);
|
|
512
|
+
return true;
|
|
513
|
+
}
|
|
503
514
|
// Si la entrega anuncia archivos, se vuelven a subir de disco antes: el
|
|
504
515
|
// proceso pudo morir entre guardarla y subirlos, y anclar un texto que
|
|
505
516
|
// anuncia archivos que el buzón no tiene dejaría al cliente sin ellos.
|
|
506
517
|
// Subir otra vez lo mismo no ocupa más.
|
|
507
|
-
const archivos = deps.archivosGuardados?.(taskId, resultado) ?? [];
|
|
508
518
|
if (archivos.length > 0) await deps.panal.publishBoardJobFiles(job.id, archivos);
|
|
509
519
|
const { txHash } = await deps.panal.deliverBoardJob(job.id, resultado);
|
|
510
520
|
console.log(`[tablon] encargo #${job.id} (tarea #${taskId}) entregado al segundo intento · tx ${txHash}`);
|