@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/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) => `${name} ${usd} · ${calls} llamadas · ${days} días`,
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
- periodRow(name: string, usd: string, calls: string, days: string): string;
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;