@trazum/cli 1.36.0 → 1.38.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trazum/cli",
3
- "version": "1.36.0",
3
+ "version": "1.38.0",
4
4
  "description": "Trazum CLI: find where your LLM bill goes, price every finding per month, and enforce token budgets in CI.",
5
5
  "license": "MIT",
6
6
  "author": "David Mu\u00f1oz Rey",
@@ -37,7 +37,7 @@
37
37
  "prepublishOnly": "npm run build && npm test"
38
38
  },
39
39
  "dependencies": {
40
- "@trazum/core": "1.36.0"
40
+ "@trazum/core": "1.38.0"
41
41
  },
42
42
  "devDependencies": {
43
43
  "@types/node": "^26.2.0",
package/src/i18n/en.ts CHANGED
@@ -39,6 +39,7 @@ ${bold('USAGE')}
39
39
  trazum eval <file> --cases <file> [options]
40
40
  trazum eval <file> --cases <file> --export promptfoo -o suite.json
41
41
  trazum route <log.jsonl> --prompt-file <file> --cases <file> --yes
42
+ trazum plan <log.jsonl|dir> [options]
42
43
  trazum diff <before> <after> [options]
43
44
  trazum diff --all <dir> <dir> [options]
44
45
  trazum rank <dir> [options]
@@ -78,6 +79,16 @@ ${bold('OPTIONS FOR rank')}
78
79
  --model, --calls, Price the recoverable tokens, as in optimize.
79
80
  --output-tokens, --batch
80
81
  --prompt <name> Which marked prompt to take from each source file.
82
+ --by-source The fleet: one summary per service from the
83
+ config's "sources" block (name → glob patterns
84
+ over log paths), plus a rollup naming the source
85
+ where the money is. Shares compare totals, and
86
+ when the sources' logs cover different periods
87
+ the report says so rather than letting a 3-day
88
+ log look cheap beside a 30-day one. Budgets per
89
+ service live in spend.bySource and fail the run
90
+ naming the service. Files matching no pattern
91
+ are named, never silently dropped.
81
92
  --markdown-out <file> Also write the ranking as Markdown, for a CI job
82
93
  summary or a pull request comment.
83
94
  --json The ranking as data.
@@ -289,6 +300,23 @@ ${bold('OPTIONS FOR profile')}
289
300
  "label" (which workload), "session" (which conversation — grouped by, never
290
301
  printed), "stop_reason"/"finish_reason" (answers cut off at max_tokens).
291
302
 
303
+ ${bold('OPTIONS FOR plan')}
304
+ --min-usd <n> Leave out actions worth less than n dollars. How
305
+ many were left out is stated, never silent.
306
+ -o, --out <file> Save the plan as dated JSON — the file
307
+ "trazum verify" will later hold it to.
308
+ --markdown-out <file> Also write the plan as Markdown, for a CI job
309
+ summary or a pull request comment.
310
+ --pricing <file> Local price overlay, as everywhere else.
311
+ --json The plan as data.
312
+
313
+ Reads a usage log and turns the report's findings into a ranked plan: route
314
+ this, batch that, fix the truncation pair, look at the cache. The money is
315
+ composed correctly — route and batch on the same slice arrive combined,
316
+ never summed — and every action names what the log cannot confirm, because
317
+ a plan that hides its assumptions is advice pretending to be arithmetic.
318
+ Projected savings and money already spent are separate totals throughout.
319
+
292
320
  ${bold('OPTIONS FOR route')}
293
321
  --prompt-file <file> The prompt those calls send. Not --prompt, which
294
322
  names a marked prompt inside a source file.
@@ -1227,6 +1255,31 @@ ${bold('EXAMPLES')}
1227
1255
  'A ✗ is not a defect in the log; it is a finding this log cannot support yet. The README\'s recording recipe carries every field above.',
1228
1256
  dryRunNoGates: () =>
1229
1257
  '--dry-run produces no bill, so a gate beside it would exit green having judged nothing. Run the gates without --dry-run.',
1258
+ bySourceNeedsConfig: () =>
1259
+ '--by-source reads the "sources" block in trazum.config.json — a name per service, each with glob patterns over log paths — and this config has none. Name at least one source.',
1260
+ bySourceNothingMatched: (sources) =>
1261
+ 'No log file matched any source pattern. The sources configured: ${sources}. Patterns match the paths as given on the command line.'.replace('${sources}', sources),
1262
+ fleetHeading: (count, total, calls) => `The fleet: ${count} sources · ${total} · ${calls}`,
1263
+ fleetRow: (name, usd, share, calls, span) => `${name} ${usd} ${share} of the fleet · ${calls} · ${span}`,
1264
+ fleetSpan: (days) => `${days} days`,
1265
+ fleetNoClock: () => 'no clock',
1266
+ fleetWorst: (name, usd, share) =>
1267
+ `${name} is where the money is: ${usd}, ${share} of the fleet's total.`,
1268
+ fleetMismatchedSpans: () =>
1269
+ 'These sources cover different periods, so the shares above compare totals, not rates — a 3-day log looks cheap next to a 30-day one for reasons that have nothing to do with cost. Each row states its own span.',
1270
+ fleetSplitBrain: (label, detail) =>
1271
+ `The same workload runs on different models in different sources — ${label}: ${detail}. Same job, different rate cards; whether that is a decision or an accident is not in the logs.`,
1272
+ fleetCacheUnderwater: (name, usd) =>
1273
+ `Caching pays for the fleet overall but loses ${usd} in ${name} — the aggregate verdict was hiding it.`,
1274
+ fleetUnmatched: (file) =>
1275
+ `${file} matched no source pattern, so it is in no report above — spend missing from every bill until a pattern covers it.`,
1276
+ fleetFooter: () =>
1277
+ 'Summaries per source; the full report for one service is "trazum profile <its logs>". Same thresholds, same findings, one source at a time.',
1278
+ fleetBudgetOk: (name, usd, max) => `Within budget: ${name} spent ${usd} against its ${max} in spend.bySource.`,
1279
+ fleetBudgetFailed: (name, usd, max) =>
1280
+ `FAILED — ${name} spent ${usd} against its budget of ${max} in spend.bySource. The fleet total can be fine while one service bleeds; this gate names which.`,
1281
+ fleetBudgetMissing: (name) =>
1282
+ `${name} has a budget in spend.bySource and no logs matched it in this run, so nothing was measured for it. Not a pass: a service that did not appear is not a service under budget.`,
1230
1283
  coverageHeading: () => 'What this log cannot answer yet',
1231
1284
  needsLabel: (seen) =>
1232
1285
  `"label" on ${seen} records: without it every workload is one row, so no per-workload spend, no drill-down, and the levers describe a mixture rather than a decision.`,
@@ -1310,6 +1363,55 @@ ${bold('EXAMPLES')}
1310
1363
  `${label} on ${model}: ${single} of ${sessions} conversations ended after their first turn and spent ${usd} writing a cache that nothing in this log ever read. Within the conversation, across conversations — no read anywhere, so those writes bought nothing. Caching a one-shot call is pure write premium; stop marking these calls with cache_control.`,
1311
1364
  },
1312
1365
 
1366
+ plan: {
1367
+ noTarget: () =>
1368
+ 'Point this at a usage log or a directory of them: trazum plan usage.jsonl. It turns the report into a ranked plan — what to do first, what each action is worth, and what the log cannot confirm about it.',
1369
+ nothingPriced: () =>
1370
+ 'This log priced nothing — no call in it matched a model in the catalogue. A plan over zero dollars would be advice about nothing; check the log with "trazum profile" first.',
1371
+ heading: (actions, total) => `The plan: ${actions} actions against a ${total} bill`,
1372
+ totals: (projected, staked) =>
1373
+ `${projected} projected savings, on assumptions listed below. ${staked} already spent on problems this plan names — measured, not projected.`,
1374
+ noClock: () =>
1375
+ 'No timestamps in this log, so every figure is per this log, not per any period.',
1376
+ projected: (usd) => `${usd} projected`,
1377
+ staked: (usd) => `${usd} already spent`,
1378
+ action: (kind, label, model) => {
1379
+ const verb =
1380
+ kind === 'route'
1381
+ ? 'Route'
1382
+ : kind === 'batch'
1383
+ ? 'Batch'
1384
+ : kind === 'route+batch'
1385
+ ? 'Route and batch'
1386
+ : kind === 'fix-truncation'
1387
+ ? 'Fix the truncation retries on'
1388
+ : 'Look at the cache on';
1389
+ return `${verb} ${label} (${model})`;
1390
+ },
1391
+ routeTo: (model) => `to ${model} — combined with batching where both apply, never summed`,
1392
+ assume: (assumption) => {
1393
+ switch (assumption.kind) {
1394
+ case 'model-capability':
1395
+ return `assumes ${assumption.model} can do this work — the log prices the move, it cannot judge the answers`;
1396
+ case 'batch-window':
1397
+ return 'assumes these calls can wait for a batch window';
1398
+ case 'retry-pattern-real':
1399
+ return 'assumes the retry pattern is real — the log sees shapes, not content';
1400
+ case 'max-tokens-fits':
1401
+ return 'assumes a max_tokens the answers fit in removes the pair';
1402
+ case 'traffic-pattern-holds':
1403
+ return 'assumes the traffic pattern holds — a cache that lost money on this log may pay on different traffic';
1404
+ }
1405
+ },
1406
+ check: (command) => `check it: ${command}`,
1407
+ filtered: (count, minUsd, worth) =>
1408
+ `${count} actions under ${minUsd}, worth ${worth} together, left out by --min-usd — left out of this document entirely, not disproved.`,
1409
+ footer: () =>
1410
+ 'Ranked by money, projected or already spent alike. The assumptions are yours to answer: this plan is arithmetic over the log, not knowledge of your product.',
1411
+ wrote: (path) =>
1412
+ `Plan written to ${path}, dated. Keep it: a prediction nobody wrote down is a prediction nobody can be held to.`,
1413
+ },
1414
+
1313
1415
  route: {
1314
1416
  noTarget: () =>
1315
1417
  'Point this at a usage log and a prompt: trazum route usage.jsonl --prompt-file prompts/support.txt --cases cases.txt --yes. It finds the slice worth the most, then measures whether the cheaper model still does the job. The flag is --prompt-file and not --prompt, because --prompt names a marked prompt inside a source file everywhere else in this tool.',
package/src/i18n/es.ts CHANGED
@@ -26,6 +26,7 @@ ${bold('USO')}
26
26
  trazum eval <fichero> --cases <fichero> [opciones]
27
27
  trazum eval <fichero> --cases <fichero> --export promptfoo -o suite.json
28
28
  trazum route <log.jsonl> --prompt-file <fichero> --cases <fichero> --yes
29
+ trazum plan <log.jsonl|dir> [opciones]
29
30
  trazum diff <antes> <después> [opciones]
30
31
  trazum diff --all <dir> <dir> [opciones]
31
32
  trazum rank <dir> [opciones]
@@ -66,6 +67,18 @@ ${bold('OPCIONES DE rank')}
66
67
  --model, --calls, Calcula el coste de los tokens recuperables, como
67
68
  --output-tokens, --batch en optimize.
68
69
  --prompt <nombre> Qué prompt marcado tomar de cada fichero de código.
70
+ --by-source La flota: un resumen por servicio desde el
71
+ bloque "sources" de la config (nombre → patrones
72
+ glob sobre rutas de registros), más un rollup
73
+ que nombra la fuente donde está el dinero. Los
74
+ porcentajes comparan totales, y cuando los
75
+ registros cubren periodos distintos el informe
76
+ lo dice en vez de dejar que un registro de 3
77
+ días parezca barato junto a uno de 30. Los
78
+ presupuestos por servicio viven en
79
+ spend.bySource y hacen fallar la ejecución
80
+ nombrando el servicio. Los ficheros sin patrón
81
+ se nombran, nunca se descartan en silencio.
69
82
  --markdown-out <fichero> Escribe además el ranking en Markdown, para el
70
83
  resumen de un job de CI o un comentario de PR.
71
84
  --json El ranking como datos.
@@ -292,6 +305,25 @@ ${bold('OPCIONES DE profile')}
292
305
  nunca se imprime), "stop_reason"/"finish_reason" (respuestas cortadas en
293
306
  max_tokens).
294
307
 
308
+ ${bold('OPCIONES DE plan')}
309
+ --min-usd <n> Deja fuera las acciones que valen menos de n
310
+ dólares. Cuántas quedaron fuera se dice, nunca
311
+ en silencio.
312
+ -o, --out <fichero> Guarda el plan como JSON fechado — el fichero al
313
+ que "trazum verify" lo atará después.
314
+ --markdown-out <fichero> Escribe además el plan como Markdown, para un
315
+ resumen de CI o un comentario de pull request.
316
+ --pricing <fichero> Tarifas locales superpuestas, como en el resto.
317
+ --json El plan como datos.
318
+
319
+ Lee un registro de uso y convierte los hallazgos del informe en un plan
320
+ ordenado: enruta esto, agrupa aquello, arregla el par de truncados, mira la
321
+ caché. El dinero está compuesto correctamente — ruta y batch sobre la misma
322
+ porción llegan combinados, nunca sumados — y cada acción nombra lo que el
323
+ registro no puede confirmar, porque un plan que esconde sus supuestos es un
324
+ consejo haciéndose pasar por aritmética. El ahorro proyectado y el dinero ya
325
+ gastado son totales separados en todas partes.
326
+
295
327
  ${bold('OPCIONES DE route')}
296
328
  --prompt-file <fichero> El prompt que mandan esas llamadas. No --prompt,
297
329
  que nombra un prompt marcado dentro de un fuente.
@@ -1243,6 +1275,31 @@ ${bold('EJEMPLOS')}
1243
1275
  'Una ✗ no es un defecto del registro; es un hallazgo que este registro aún no puede sostener. La receta de registro del README lleva todos los campos de arriba.',
1244
1276
  dryRunNoGates: () =>
1245
1277
  '--dry-run no produce factura, así que un gate a su lado saldría en verde sin haber juzgado nada. Corre los gates sin --dry-run.',
1278
+ bySourceNeedsConfig: () =>
1279
+ '--by-source lee el bloque "sources" de trazum.config.json — un nombre por servicio, cada uno con patrones glob sobre rutas de registros — y esta config no tiene ninguno. Nombra al menos una fuente.',
1280
+ bySourceNothingMatched: (sources) =>
1281
+ 'Ningún fichero de registro coincidió con ningún patrón de fuente. Las fuentes configuradas: ${sources}. Los patrones casan con las rutas tal como se dan en la línea de comandos.'.replace('${sources}', sources),
1282
+ fleetHeading: (count, total, calls) => `La flota: ${count} fuentes · ${total} · ${calls}`,
1283
+ fleetRow: (name, usd, share, calls, span) => `${name} ${usd} ${share} de la flota · ${calls} · ${span}`,
1284
+ fleetSpan: (days) => `${days} días`,
1285
+ fleetNoClock: () => 'sin reloj',
1286
+ fleetWorst: (name, usd, share) =>
1287
+ `${name} es donde está el dinero: ${usd}, el ${share} del total de la flota.`,
1288
+ fleetMismatchedSpans: () =>
1289
+ 'Estas fuentes cubren periodos distintos, así que los porcentajes de arriba comparan totales, no ritmos — un registro de 3 días parece barato junto a uno de 30 por motivos que nada tienen que ver con el coste. Cada fila indica su propio periodo.',
1290
+ fleetSplitBrain: (label, detail) =>
1291
+ `La misma carga corre en modelos distintos en fuentes distintas — ${label}: ${detail}. Mismo trabajo, tarifas distintas; si es una decisión o un accidente no está en los registros.`,
1292
+ fleetCacheUnderwater: (name, usd) =>
1293
+ `La caché es rentable para la flota en conjunto pero pierde ${usd} en ${name} — el veredicto agregado lo escondía.`,
1294
+ fleetUnmatched: (file) =>
1295
+ `${file} no coincidió con ningún patrón de fuente, así que no está en ningún informe de arriba — gasto ausente de todas las facturas hasta que un patrón lo cubra.`,
1296
+ fleetFooter: () =>
1297
+ 'Resúmenes por fuente; el informe completo de un servicio es "trazum profile <sus registros>". Mismos umbrales, mismos hallazgos, una fuente cada vez.',
1298
+ fleetBudgetOk: (name, usd, max) => `Dentro de presupuesto: ${name} gastó ${usd} contra su ${max} en spend.bySource.`,
1299
+ fleetBudgetFailed: (name, usd, max) =>
1300
+ `FALLÓ — ${name} gastó ${usd} contra su presupuesto de ${max} en spend.bySource. El total de la flota puede estar bien mientras un servicio sangra; este gate nombra cuál.`,
1301
+ fleetBudgetMissing: (name) =>
1302
+ `${name} tiene presupuesto en spend.bySource y ningún registro coincidió con él en esta ejecución, así que no se midió nada. No es un aprobado: un servicio que no apareció no es un servicio dentro de presupuesto.`,
1246
1303
  coverageHeading: () => 'Lo que este registro todavía no puede responder',
1247
1304
  needsLabel: (seen) =>
1248
1305
  `"label" en ${seen} registros: sin él todas las cargas son una sola fila, así que no hay gasto por carga, ni zoom, y las palancas describen una mezcla en vez de una decisión.`,
@@ -1326,6 +1383,55 @@ ${bold('EJEMPLOS')}
1326
1383
  `${label} en ${model}: ${single} de ${sessions} conversaciones terminaron tras su primer turno y gastaron ${usd} escribiendo una caché que nada en este registro leyó jamás. Dentro de la conversación, entre conversaciones — ninguna lectura en ningún sitio, así que esas escrituras no compraron nada. Cachear una llamada de un solo uso es puro sobreprecio de escritura; deja de marcar estas llamadas con cache_control.`,
1327
1384
  },
1328
1385
 
1386
+ plan: {
1387
+ noTarget: () =>
1388
+ 'Apunta esto a un registro de uso o a un directorio de ellos: trazum plan usage.jsonl. Convierte el informe en un plan ordenado — qué hacer primero, cuánto vale cada acción y qué no puede confirmar el registro sobre ella.',
1389
+ nothingPriced: () =>
1390
+ 'Este registro no tasó nada — ninguna llamada coincide con un modelo del catálogo. Un plan sobre cero dólares sería un consejo sobre nada; revisa el registro primero con "trazum profile".',
1391
+ heading: (actions, total) => `El plan: ${actions} acciones contra una factura de ${total}`,
1392
+ totals: (projected, staked) =>
1393
+ `${projected} de ahorro proyectado, sobre los supuestos listados abajo. ${staked} ya gastados en problemas que este plan nombra — medido, no proyectado.`,
1394
+ noClock: () =>
1395
+ 'Este registro no tiene marcas de tiempo, así que cada cifra es por este registro, no por ningún período.',
1396
+ projected: (usd) => `${usd} proyectados`,
1397
+ staked: (usd) => `${usd} ya gastados`,
1398
+ action: (kind, label, model) => {
1399
+ const verb =
1400
+ kind === 'route'
1401
+ ? 'Enruta'
1402
+ : kind === 'batch'
1403
+ ? 'Agrupa en batch'
1404
+ : kind === 'route+batch'
1405
+ ? 'Enruta y agrupa'
1406
+ : kind === 'fix-truncation'
1407
+ ? 'Arregla los reintentos por truncado de'
1408
+ : 'Mira la caché de';
1409
+ return `${verb} ${label} (${model})`;
1410
+ },
1411
+ routeTo: (model) => `a ${model} — combinado con el batch donde aplican los dos, nunca sumado`,
1412
+ assume: (assumption) => {
1413
+ switch (assumption.kind) {
1414
+ case 'model-capability':
1415
+ return `supone que ${assumption.model} puede hacer este trabajo — el registro tasa el cambio, no puede juzgar las respuestas`;
1416
+ case 'batch-window':
1417
+ return 'supone que estas llamadas pueden esperar una ventana de batch';
1418
+ case 'retry-pattern-real':
1419
+ return 'supone que el patrón de reintentos es real — el registro ve formas, no contenido';
1420
+ case 'max-tokens-fits':
1421
+ return 'supone que un max_tokens en el que quepan las respuestas elimina el par';
1422
+ case 'traffic-pattern-holds':
1423
+ return 'supone que el patrón de tráfico se mantiene — una caché que perdió dinero en este registro puede rendir con otro tráfico';
1424
+ }
1425
+ },
1426
+ check: (command) => `compruébalo: ${command}`,
1427
+ filtered: (count, minUsd, worth) =>
1428
+ `${count} acciones por debajo de ${minUsd}, que juntas valen ${worth}, quedaron fuera por --min-usd — fuera de este documento por completo, no refutadas.`,
1429
+ footer: () =>
1430
+ 'Ordenado por dinero, proyectado o ya gastado por igual. Los supuestos los respondes tú: este plan es aritmética sobre el registro, no conocimiento de tu producto.',
1431
+ wrote: (path) =>
1432
+ `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.`,
1433
+ },
1434
+
1329
1435
  route: {
1330
1436
  noTarget: () =>
1331
1437
  'Apunta esto a un registro de uso y a un prompt: trazum route usage.jsonl --prompt-file prompts/soporte.txt --cases casos.txt --yes. Busca la porción que más vale y mide si el modelo más barato sigue haciendo el trabajo. El flag es --prompt-file y no --prompt, porque en el resto de la herramienta --prompt nombra un prompt marcado dentro de un fichero fuente.',
package/src/i18n/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { EvalVerdict, Locale, RuleLevel } from '@trazum/core';
1
+ import type { EvalVerdict, Locale, PlanActionKind, PlanAssumption, RuleLevel } from '@trazum/core';
2
2
 
3
3
  /**
4
4
  * The CLI's own message catalogue.
@@ -975,6 +975,26 @@ export interface CliMessages {
975
975
  dryRunNoCacheTraffic(): string;
976
976
  dryRunFooter(): string;
977
977
  dryRunNoGates(): string;
978
+ /**
979
+ * `--by-source`: the fleet. One summary per service, the rollup naming
980
+ * the worst offender, cross-source findings a merged bill cannot make,
981
+ * and per-source budgets that fail naming the service.
982
+ */
983
+ bySourceNeedsConfig(): string;
984
+ bySourceNothingMatched(sources: string): string;
985
+ fleetHeading(count: string, total: string, calls: string): string;
986
+ fleetRow(name: string, usd: string, share: string, calls: string, span: string): string;
987
+ fleetSpan(days: string): string;
988
+ fleetNoClock(): string;
989
+ fleetWorst(name: string, usd: string, share: string): string;
990
+ fleetMismatchedSpans(): string;
991
+ fleetSplitBrain(label: string, detail: string): string;
992
+ fleetCacheUnderwater(name: string, usd: string): string;
993
+ fleetUnmatched(file: string): string;
994
+ fleetFooter(): string;
995
+ fleetBudgetOk(name: string, usd: string, max: string): string;
996
+ fleetBudgetFailed(name: string, usd: string, max: string): string;
997
+ fleetBudgetMissing(name: string): string;
978
998
  coverageHeading(): string;
979
999
  needsLabel(seen: string): string;
980
1000
  needsSession(seen: string): string;
@@ -1018,6 +1038,40 @@ export interface CliMessages {
1018
1038
  singleTurnCeiling(label: string, model: string, single: string, sessions: string, usd: string): string;
1019
1039
  singleTurnConfirmed(label: string, model: string, single: string, sessions: string, usd: string): string;
1020
1040
  };
1041
+ /**
1042
+ * `trazum plan <log>` — not a list of findings, a ranked plan of what to do.
1043
+ *
1044
+ * The report names what it found; the plan ranks what to do about it, with
1045
+ * the money composed correctly (route and batch on one slice combined,
1046
+ * never summed) and every action carrying what the log cannot confirm.
1047
+ * Projected savings and measured stakes are separate columns throughout:
1048
+ * "what you would save" and "what you already paid" merged into one number
1049
+ * is a number that is neither.
1050
+ */
1051
+ plan: {
1052
+ noTarget(): string;
1053
+ /** The log priced nothing — a plan over zero calls would be advice about nothing. */
1054
+ nothingPriced(): string;
1055
+ heading(actions: string, total: string): string;
1056
+ totals(projected: string, staked: string): string;
1057
+ /** No timestamps: the figures are per this log, not per any period. */
1058
+ noClock(): string;
1059
+ projected(usd: string): string;
1060
+ staked(usd: string): string;
1061
+ /** One action line: what to do, to which workload, on which model. */
1062
+ action(kind: PlanActionKind, label: string, model: string): string;
1063
+ routeTo(model: string): string;
1064
+ /** One assumption the log cannot confirm, localized from its typed form. */
1065
+ assume(assumption: PlanAssumption): string;
1066
+ /** The command that can check the assumption, when one exists. */
1067
+ check(command: string): string;
1068
+ /** Actions below --min-usd, counted out loud rather than dropped silently. */
1069
+ filtered(count: string, minUsd: string, worth: string): string;
1070
+ footer(): string;
1071
+ /** The plan saved as dated JSON — what 1.39's verify will hold it to. */
1072
+ wrote(path: string): string;
1073
+ };
1074
+
1021
1075
  /**
1022
1076
  * `trazum route` — the loop the levers section could only point at.
1023
1077
  *