@trazum/cli 1.40.0 → 1.42.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 +2 -0
- package/dist/connect.d.ts +72 -0
- package/dist/connect.d.ts.map +1 -0
- package/dist/connect.js +204 -0
- package/dist/connect.js.map +1 -0
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +99 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +101 -1
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/types.d.ts +61 -1
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.js +379 -72
- package/dist/index.js.map +1 -1
- package/dist/store-fs.d.ts +59 -0
- package/dist/store-fs.d.ts.map +1 -0
- package/dist/store-fs.js +145 -0
- package/dist/store-fs.js.map +1 -0
- package/package.json +2 -2
- package/src/connect.ts +245 -0
- package/src/i18n/en.ts +125 -1
- package/src/i18n/es.ts +127 -1
- package/src/i18n/types.ts +63 -1
- package/src/index.ts +503 -67
- package/src/store-fs.ts +157 -0
package/src/i18n/es.ts
CHANGED
|
@@ -29,6 +29,8 @@ ${bold('USO')}
|
|
|
29
29
|
trazum plan <log.jsonl|dir> [opciones]
|
|
30
30
|
trazum verify <plan.json> --against <nuevo.jsonl|dir> [opciones]
|
|
31
31
|
trazum history <dir-de-informes-guardados> [opciones]
|
|
32
|
+
trazum connect <anthropic|openai> [opciones]
|
|
33
|
+
trazum store [--prune] [opciones]
|
|
32
34
|
trazum diff <antes> <después> [opciones]
|
|
33
35
|
trazum diff --all <dir> <dir> [opciones]
|
|
34
36
|
trazum rank <dir> [opciones]
|
|
@@ -326,7 +328,66 @@ ${bold('OPCIONES DE plan')}
|
|
|
326
328
|
consejo haciéndose pasar por aritmética. El ahorro proyectado y el dinero ya
|
|
327
329
|
gastado son totales separados en todas partes.
|
|
328
330
|
|
|
331
|
+
${bold('OPCIONES DE store')}
|
|
332
|
+
--prune Borra las mediciones más antiguas que la política
|
|
333
|
+
de retención y compacta el log a lo que el
|
|
334
|
+
almacén ya resuelve. Dice qué se fue.
|
|
335
|
+
--keep <n>d Retención para esta ejecución, si la config no
|
|
336
|
+
tiene ninguna.
|
|
337
|
+
--dry-run Con --prune: dice qué se iría y no borra nada.
|
|
338
|
+
--json El inventario como datos.
|
|
339
|
+
|
|
340
|
+
Dice qué guarda el almacén local: cuántas mediciones, sobre qué período, por
|
|
341
|
+
proveedor, y qué se llevaría una poda. El almacén guarda agregados y campos
|
|
342
|
+
de facturación — nunca texto de prompt, nunca texto de respuesta, nunca una
|
|
343
|
+
credencial — así que es un fichero que un equipo puede respaldar sin una
|
|
344
|
+
revisión de privacidad.
|
|
345
|
+
|
|
346
|
+
La poda es la única operación de aquí que destruye algo, así que se niega a
|
|
347
|
+
correr sin política de retención: pon "store": {"keepDays": 90} en la config
|
|
348
|
+
o pasa --keep. Borrar mediciones con una política que nadie escribió no es un
|
|
349
|
+
valor por defecto que nadie deba recibir por accidente.
|
|
350
|
+
|
|
351
|
+
${bold('OPCIONES DE connect')}
|
|
352
|
+
--since <cuándo> La ventana que se descarga. Un día UTC, una marca
|
|
353
|
+
--until <cuándo> ISO, una ventana relativa (7d, 24h) o "now". Por
|
|
354
|
+
defecto, los últimos 30 días.
|
|
355
|
+
--dry-run Dice qué se llamaría y de qué variable de entorno
|
|
356
|
+
saldría la clave. No envía nada y no necesita
|
|
357
|
+
credencial.
|
|
358
|
+
--payload <fichero> Tasa un payload de uso que ya tengas, en vez de
|
|
359
|
+
descargar uno. Sin credencial y sin red — la misma
|
|
360
|
+
aritmética sobre la misma forma.
|
|
361
|
+
--store Guarda lo descargado en el almacén local, para que
|
|
362
|
+
la próxima vez no haya que bajarlo otra vez y
|
|
363
|
+
"trazum history --store" tenga una serie.
|
|
364
|
+
-o, --out <fichero> Guarda el informe tasado como JSON.
|
|
365
|
+
--markdown-out <fichero> Lo escribe además como Markdown, para CI.
|
|
366
|
+
--json El informe como datos.
|
|
367
|
+
|
|
368
|
+
Lee tu factura desde la API de uso del proveedor, para que nadie tenga que
|
|
369
|
+
exportar nada a mano. La credencial se lee del entorno en el momento de la
|
|
370
|
+
llamada y nunca se guarda, nunca se imprime y nunca se escribe en un fichero
|
|
371
|
+
de configuración: define TRAZUM_ANTHROPIC_ADMIN_KEY o TRAZUM_OPENAI_ADMIN_KEY.
|
|
372
|
+
Cada proveedor necesita la clave más estrecha que pueda leer un informe de
|
|
373
|
+
uso, y una clave de API normal no puede.
|
|
374
|
+
|
|
375
|
+
Estas APIs sirven sumas sobre una ventana, no una fila por llamada, así que
|
|
376
|
+
un informe conectado es un informe restringido y lo dice: los totales, el
|
|
377
|
+
reparto por modelo, la serie por día y el veredicto de caché están todos
|
|
378
|
+
disponibles, y los hallazgos por llamada — formas de entrada, reintentos por
|
|
379
|
+
truncado, conversaciones, presión de contexto — se listan como no disponibles
|
|
380
|
+
con lo que los desbloquearía. Un límite de tasa, un tope de páginas o un
|
|
381
|
+
cursor caducado devuelven lo que llegó con el hueco nombrado, nunca un total
|
|
382
|
+
que describe en silencio menos tráfico del que pediste.
|
|
383
|
+
|
|
329
384
|
${bold('OPCIONES DE history')}
|
|
385
|
+
--store Construye la serie desde el almacén local en vez
|
|
386
|
+
de un directorio de informes guardados. Las
|
|
387
|
+
fuentes agregadas no llevan label, así que la
|
|
388
|
+
serie por label está ausente y se dice — las de
|
|
389
|
+
cuota de modelo y de caché son para lo que existe
|
|
390
|
+
una serie, y funcionan enteras.
|
|
330
391
|
--markdown-out <fichero> Escribe además la serie como Markdown, para un
|
|
331
392
|
resumen de CI o un comentario de pull request.
|
|
332
393
|
--json La historia como datos.
|
|
@@ -1470,13 +1531,76 @@ ${bold('EJEMPLOS')}
|
|
|
1470
1531
|
`Plan escrito en ${path}, con fecha. Guárdalo: una predicción que nadie apuntó es una predicción que no se le puede exigir a nadie.`,
|
|
1471
1532
|
},
|
|
1472
1533
|
|
|
1534
|
+
store: {
|
|
1535
|
+
appended: (count, dir) => `Guardadas ${count} mediciones en ${dir}.`,
|
|
1536
|
+
empty: (dir) =>
|
|
1537
|
+
`El almacén de ${dir} está vacío. Llénalo con "trazum connect <proveedor> --store" — eso es un estado, no un error.`,
|
|
1538
|
+
heading: (records, usd, from, to) =>
|
|
1539
|
+
`El almacén: ${records} mediciones · ${usd} · ${from} → ${to}`,
|
|
1540
|
+
providerRow: (provider, records, span, models) =>
|
|
1541
|
+
`${provider} ${records} mediciones · ${span} · ${models} modelos`,
|
|
1542
|
+
holds: (files) =>
|
|
1543
|
+
`Guardado en ${files} ficheros: recuentos de tokens, dólares facturados y los identificadores de workspace y clave de la propia cuenta. Nunca texto de prompt, nunca texto de respuesta, nunca una credencial — esto es un fichero que puedes respaldar sin una revisión de privacidad.`,
|
|
1544
|
+
possiblyDouble: (count) =>
|
|
1545
|
+
`${count} registros no se pudieron distinguir de otro — una ventana de longitud cero, o un registro que no nombra modelo. Se guardan enteros en vez de fundirse, así que un total construido sobre ellos puede contar el mismo gasto dos veces. Decirlo es mejor que un número más pequeño que nadie puede comprobar.`,
|
|
1546
|
+
unknownVersion: (count) =>
|
|
1547
|
+
`${count} registros vienen de un esquema más nuevo del que esta versión conoce, así que se conservan y quedan fuera de las cifras de arriba en vez de adivinarse. Actualiza para leerlos.`,
|
|
1548
|
+
unreadable: (file, line) =>
|
|
1549
|
+
`${file} línea ${line} no se pudo parsear, así que no está en las cifras de arriba. El resto del fichero sí se leyó — una línea rota no puede costar un mes.`,
|
|
1550
|
+
retention: (days) => `Retención: ${days} días, de "store.keepDays". Ejecuta "trazum store --prune" para aplicarla.`,
|
|
1551
|
+
noRetention: () =>
|
|
1552
|
+
'No hay política de retención configurada, así que nunca se borra nada por su cuenta. Pon "store": {"keepDays": 90} cuando quieras una.',
|
|
1553
|
+
pruneNeedsPolicy: () =>
|
|
1554
|
+
'Podar necesita una política de retención: pon "store": {"keepDays": 90} en trazum.config.json, o pasa --keep 90d para esta ejecución. Borrar mediciones con una política que nadie escribió no es un valor por defecto que debas recibir por accidente.',
|
|
1555
|
+
pruneDryRun: (count, days, span, usd) =>
|
|
1556
|
+
span === null
|
|
1557
|
+
? `Nada es más antiguo que ${days} días, así que una poda no borraría nada.`
|
|
1558
|
+
: `Una poda borraría ${count} mediciones de más de ${days} días, que cubren ${span} y ${usd} de gasto medido. No se borró nada — esto era --dry-run.`,
|
|
1559
|
+
pruned: (count, days, span, usd, kept) =>
|
|
1560
|
+
span === null
|
|
1561
|
+
? `Nada era más antiguo que ${days} días. ${kept} mediciones conservadas, y el log compactado.`
|
|
1562
|
+
: `Borradas ${count} mediciones de más de ${days} días, que cubren ${span} y ${usd} de gasto medido. ${kept} conservadas, y el log compactado a lo que el almacén ya resolvía.`,
|
|
1563
|
+
},
|
|
1564
|
+
|
|
1565
|
+
connect: {
|
|
1566
|
+
noTarget: (providers) =>
|
|
1567
|
+
`Nombra un proveedor del que leer tu factura: trazum connect anthropic. Disponibles: ${providers}. La credencial sale del entorno y nunca se guarda — añade --dry-run para ver exactamente qué se llamaría y de qué variable saldría.`,
|
|
1568
|
+
unknownProvider: (id, providers) =>
|
|
1569
|
+
`No hay conector para "${id}". Los que existen son: ${providers}.`,
|
|
1570
|
+
dryRun: (provider, from, to, envVars, keyKind) =>
|
|
1571
|
+
`Leería el uso de ${provider} del ${from} al ${to}, usando ${keyKind} tomada de ${envVars}. No se envió nada y no hizo falta ninguna credencial para imprimir esto.`,
|
|
1572
|
+
heading: (provider, from, to, usd, calls) =>
|
|
1573
|
+
calls === null
|
|
1574
|
+
? `${provider} · ${from} → ${to} · ${usd}`
|
|
1575
|
+
: `${provider} · ${from} → ${to} · ${usd} · ${calls} llamadas`,
|
|
1576
|
+
modelRow: (model, usd, share, calls) =>
|
|
1577
|
+
calls === null ? `${model} ${usd} ${share}` : `${model} ${usd} ${share} · ${calls} llamadas`,
|
|
1578
|
+
nothingBilled: () =>
|
|
1579
|
+
'El proveedor no facturó nada en esta ventana. Eso es una medición, no un error — ensánchala con --since si esperabas tráfico.',
|
|
1580
|
+
cachePaid: (saved) => `La caché se pagó sola: ${saved} menos de lo que estos tokens habrían costado como entrada normal.`,
|
|
1581
|
+
cacheLost: (added) => `La caché añadió ${added} a esta factura frente a lo que los mismos tokens habrían costado como entrada normal.`,
|
|
1582
|
+
cacheUnsettled: () =>
|
|
1583
|
+
'Esta fuente no dijo con qué TTL se escribió la caché, así que se asumió la tarifa barata y el veredicto cambia con la otra. Sin resolver, no resuelto a tu favor.',
|
|
1584
|
+
noCallCount: (provider) =>
|
|
1585
|
+
`El informe de uso de ${provider} sirve sumas de tokens y ningún recuento de peticiones, así que aquí no hay número de llamadas ni media por llamada. Un cero se leería como "sin tráfico", así que no se imprime nada en su lugar.`,
|
|
1586
|
+
unpriced: (model, tokens) =>
|
|
1587
|
+
`${model} no está en el catálogo de precios, así que sus ${tokens} tokens se cuentan y su dinero no. Añádelo con --pricing en vez de leer el total como completo.`,
|
|
1588
|
+
gap: (detail) => `Esta ventana está incompleta: ${detail}.`,
|
|
1589
|
+
unavailable: (findings) =>
|
|
1590
|
+
`Hallazgos que esta fuente no puede sostener: ${findings}. Necesitan una fila por llamada, y una suma ha perdido las filas — un registro por llamada sí los responde.`,
|
|
1591
|
+
wrote: (path) => `Informe escrito en ${path}.`,
|
|
1592
|
+
footer: () =>
|
|
1593
|
+
'Cada cifra de aquí es el recuento de tokens que el proveedor facturó, a las tarifas del catálogo. No se estimó nada, y no se rellenó nada que el proveedor no sirviera.',
|
|
1594
|
+
},
|
|
1595
|
+
|
|
1473
1596
|
history: {
|
|
1474
1597
|
noTarget: () =>
|
|
1475
1598
|
'Apunta esto a un directorio de informes guardados: trazum history informes/. Lee los documentos --json que escribe "trazum profile" (y los planes guardados que haya al lado) y construye la serie que ninguna comparación por pares puede ver.',
|
|
1476
1599
|
needsThree: (count) =>
|
|
1477
1600
|
`Una serie necesita al menos tres informes con fecha, y este directorio tiene ${count}. Dos informes son una comparación, y "trazum profile --against" ya la hace mejor.`,
|
|
1478
1601
|
heading: (periods, from, to) => `La larga distancia: ${periods} períodos, ${from} → ${to}`,
|
|
1479
|
-
periodRow: (name, usd, calls, days) =>
|
|
1602
|
+
periodRow: (name, usd, calls, days) =>
|
|
1603
|
+
calls === null ? `${name} ${usd} · ${days} días` : `${name} ${usd} · ${calls} llamadas · ${days} días`,
|
|
1480
1604
|
runLabel: (label, periods, sinceName, from, to) =>
|
|
1481
1605
|
`${label} lleva ${periods} períodos consecutivos subiendo desde ${sinceName}: ${from} → ${to}. Una forma, no un pronóstico.`,
|
|
1482
1606
|
runModel: (model, periods, sinceName, from, to) =>
|
|
@@ -1497,6 +1621,8 @@ ${bold('EJEMPLOS')}
|
|
|
1497
1621
|
const span = first !== null && last !== null ? ` (${first} → ${last})` : '';
|
|
1498
1622
|
return `${what} se ha planificado ${appearances} veces${span} y sigue en el plan más reciente — una decisión que nadie está revisando.`;
|
|
1499
1623
|
},
|
|
1624
|
+
storeNoLabels: () =>
|
|
1625
|
+
'Esta serie viene del almacén, y una API de uso agrupa por modelo y workspace, no por carga de trabajo — así que aquí no hay serie por label en absoluto. Ausente, no vacía: nada de lo de arriba dice que una carga se moviera o dejara de moverse.',
|
|
1500
1626
|
undated: (name) => `${name} no lleva período, así que no está en ninguna línea de tiempo de arriba — nombrado, nunca absorbido en silencio.`,
|
|
1501
1627
|
unrecognized: (name) => `${name} no es ni un informe guardado ni un plan guardado, así que no está en ninguna serie de arriba.`,
|
|
1502
1628
|
footer: () =>
|
package/src/i18n/types.ts
CHANGED
|
@@ -1072,6 +1072,65 @@ export interface CliMessages {
|
|
|
1072
1072
|
wrote(path: string): string;
|
|
1073
1073
|
};
|
|
1074
1074
|
|
|
1075
|
+
/**
|
|
1076
|
+
* `trazum store` — the measurements kept on disk.
|
|
1077
|
+
*
|
|
1078
|
+
* The one part of this product that deletes something, so its copy is
|
|
1079
|
+
* written to make that visible: what is held, what a prune would take, and
|
|
1080
|
+
* a refusal when no retention policy exists to prune against.
|
|
1081
|
+
*/
|
|
1082
|
+
store: {
|
|
1083
|
+
/** Records appended by a pull that asked to keep them. */
|
|
1084
|
+
appended(count: string, dir: string): string;
|
|
1085
|
+
empty(dir: string): string;
|
|
1086
|
+
heading(records: string, usd: string, from: string, to: string): string;
|
|
1087
|
+
providerRow(provider: string, records: string, span: string, models: string): string;
|
|
1088
|
+
/** What the store holds — and what it never holds. */
|
|
1089
|
+
holds(files: string): string;
|
|
1090
|
+
/** Records the store could not tell apart, kept whole rather than merged. */
|
|
1091
|
+
possiblyDouble(count: string): string;
|
|
1092
|
+
unknownVersion(count: string): string;
|
|
1093
|
+
unreadable(file: string, line: string): string;
|
|
1094
|
+
retention(days: string): string;
|
|
1095
|
+
noRetention(): string;
|
|
1096
|
+
/** Deleting on a policy nobody wrote down is refused, never defaulted. */
|
|
1097
|
+
pruneNeedsPolicy(): string;
|
|
1098
|
+
pruneDryRun(count: string, days: string, span: string | null, usd: string): string;
|
|
1099
|
+
pruned(count: string, days: string, span: string | null, usd: string, kept: string): string;
|
|
1100
|
+
};
|
|
1101
|
+
|
|
1102
|
+
/**
|
|
1103
|
+
* `trazum connect` — the bill, read from the provider.
|
|
1104
|
+
*
|
|
1105
|
+
* A usage API serves sums, so the report is restricted on purpose and says
|
|
1106
|
+
* which findings this source cannot support. The credential copy matters as
|
|
1107
|
+
* much as the figures: Trazum borrows a key from the environment and never
|
|
1108
|
+
* stores it, and the messages here are where a user learns that.
|
|
1109
|
+
*/
|
|
1110
|
+
connect: {
|
|
1111
|
+
noTarget(providers: string): string;
|
|
1112
|
+
unknownProvider(id: string, providers: string): string;
|
|
1113
|
+
/** What would be called, with no key needed and nothing sent. */
|
|
1114
|
+
dryRun(provider: string, from: string, to: string, envVars: string, keyKind: string): string;
|
|
1115
|
+
/** `calls` is null on a source that serves no request count. */
|
|
1116
|
+
heading(provider: string, from: string, to: string, usd: string, calls: string | null): string;
|
|
1117
|
+
modelRow(model: string, usd: string, share: string, calls: string | null): string;
|
|
1118
|
+
/** A window the provider billed nothing in — not an error, and not a zero to hide. */
|
|
1119
|
+
nothingBilled(): string;
|
|
1120
|
+
cachePaid(saved: string): string;
|
|
1121
|
+
cacheLost(added: string): string;
|
|
1122
|
+
/** The write TTL was not stated, so the verdict moves under the other rate. */
|
|
1123
|
+
cacheUnsettled(): string;
|
|
1124
|
+
/** This source serves token sums and no request count. */
|
|
1125
|
+
noCallCount(provider: string): string;
|
|
1126
|
+
unpriced(model: string, tokens: string): string;
|
|
1127
|
+
/** Something the pull did not get, named rather than silently missing. */
|
|
1128
|
+
gap(detail: string): string;
|
|
1129
|
+
unavailable(findings: string): string;
|
|
1130
|
+
wrote(path: string): string;
|
|
1131
|
+
footer(): string;
|
|
1132
|
+
};
|
|
1133
|
+
|
|
1075
1134
|
/**
|
|
1076
1135
|
* `trazum history` — many reports over many periods, as one series.
|
|
1077
1136
|
*
|
|
@@ -1083,12 +1142,15 @@ export interface CliMessages {
|
|
|
1083
1142
|
/** Under three dated reports there is no series — only the comparison --against already does. */
|
|
1084
1143
|
needsThree(count: string): string;
|
|
1085
1144
|
heading(periods: string, from: string, to: string): string;
|
|
1086
|
-
|
|
1145
|
+
/** `calls` is null on a source that serves no request count. */
|
|
1146
|
+
periodRow(name: string, usd: string, calls: string | null, days: string): string;
|
|
1087
1147
|
runLabel(label: string, periods: string, sinceName: string, from: string, to: string): string;
|
|
1088
1148
|
runModel(model: string, periods: string, sinceName: string, from: string, to: string): string;
|
|
1089
1149
|
runCache(periods: string, sinceName: string, from: string, to: string): string;
|
|
1090
1150
|
/** The same action in plan after plan: a decision nobody is executing. */
|
|
1091
1151
|
repeated(kind: PlanActionKind, label: string, model: string, appearances: string, first: string | null, last: string | null): string;
|
|
1152
|
+
/** A store source carries no labels, so the label series is absent, not empty. */
|
|
1153
|
+
storeNoLabels(): string;
|
|
1092
1154
|
undated(name: string): string;
|
|
1093
1155
|
unrecognized(name: string): string;
|
|
1094
1156
|
footer(): string;
|