@trazum/cli 1.47.0 → 1.49.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/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +36 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +36 -1
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/types.d.ts +36 -0
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.js +203 -35
- package/dist/index.js.map +1 -1
- package/dist/waiver-log.d.ts +42 -0
- package/dist/waiver-log.d.ts.map +1 -0
- package/dist/waiver-log.js +74 -0
- package/dist/waiver-log.js.map +1 -0
- package/package.json +2 -2
- package/src/i18n/en.ts +53 -1
- package/src/i18n/es.ts +53 -1
- package/src/i18n/types.ts +36 -0
- package/src/index.ts +239 -37
- package/src/waiver-log.ts +81 -0
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a waiver's uses are written down.
|
|
3
|
+
*
|
|
4
|
+
* The core decides what a use means and what a run of them adds up to; this
|
|
5
|
+
* decides where the bytes go — the same split every module here follows, so
|
|
6
|
+
* `@trazum/core` stays browser-safe and the CLI keeps its monopoly on I/O.
|
|
7
|
+
*
|
|
8
|
+
* **Append-only, and never rewritten.** There is deliberately no prune, no
|
|
9
|
+
* compaction and no `--clear`: a record of decisions that the tool can erase
|
|
10
|
+
* is a record nobody can rely on, and the one thing a waiver history is for is
|
|
11
|
+
* being awkward six months later. Deleting the file is a thing a person does
|
|
12
|
+
* with `rm`, on purpose, having seen it.
|
|
13
|
+
*
|
|
14
|
+
* **A write that fails never fails the run.** The gate's job is the exit code.
|
|
15
|
+
* A read-only checkout, a full disk or a directory somebody's CI cannot create
|
|
16
|
+
* must not turn a passing build red on account of bookkeeping — the failure is
|
|
17
|
+
* reported and the gate's own verdict stands.
|
|
18
|
+
*
|
|
19
|
+
* **A line that will not parse is counted and skipped**, exactly as in the
|
|
20
|
+
* store. Losing the whole history because one line is broken would be the
|
|
21
|
+
* worst possible response; pretending the history is complete would be the
|
|
22
|
+
* second worst.
|
|
23
|
+
*/
|
|
24
|
+
import type { WaiverUse } from '@trazum/core';
|
|
25
|
+
/** One file, not one per month: a waiver history is small and read whole. */
|
|
26
|
+
export declare const WAIVER_LOG = ".trazum/waivers.jsonl";
|
|
27
|
+
export interface WaiverReadResult {
|
|
28
|
+
uses: WaiverUse[];
|
|
29
|
+
/** 1-based positions of lines that would not parse. Named, never dropped quietly. */
|
|
30
|
+
unreadable: number[];
|
|
31
|
+
/** False when the file does not exist — "nothing recorded" is not "no file". */
|
|
32
|
+
present: boolean;
|
|
33
|
+
}
|
|
34
|
+
export declare function readWaiverLog(root: string): Promise<WaiverReadResult>;
|
|
35
|
+
/**
|
|
36
|
+
* Appends one use, and swallows any failure after reporting it.
|
|
37
|
+
*
|
|
38
|
+
* Returns the error message rather than throwing, so the caller can print it
|
|
39
|
+
* beside the gate's own output without the gate ever depending on the write.
|
|
40
|
+
*/
|
|
41
|
+
export declare function appendWaiverUse(root: string, use: WaiverUse): Promise<string | null>;
|
|
42
|
+
//# sourceMappingURL=waiver-log.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waiver-log.d.ts","sourceRoot":"","sources":["../src/waiver-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAKH,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAC;AAE9C,6EAA6E;AAC7E,eAAO,MAAM,UAAU,0BAA0B,CAAC;AAElD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,EAAE,CAAC;IAClB,qFAAqF;IACrF,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,gFAAgF;IAChF,OAAO,EAAE,OAAO,CAAC;CAClB;AAED,wBAAsB,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAuB3E;AAED;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,SAAS,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAS1F"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Where a waiver's uses are written down.
|
|
3
|
+
*
|
|
4
|
+
* The core decides what a use means and what a run of them adds up to; this
|
|
5
|
+
* decides where the bytes go — the same split every module here follows, so
|
|
6
|
+
* `@trazum/core` stays browser-safe and the CLI keeps its monopoly on I/O.
|
|
7
|
+
*
|
|
8
|
+
* **Append-only, and never rewritten.** There is deliberately no prune, no
|
|
9
|
+
* compaction and no `--clear`: a record of decisions that the tool can erase
|
|
10
|
+
* is a record nobody can rely on, and the one thing a waiver history is for is
|
|
11
|
+
* being awkward six months later. Deleting the file is a thing a person does
|
|
12
|
+
* with `rm`, on purpose, having seen it.
|
|
13
|
+
*
|
|
14
|
+
* **A write that fails never fails the run.** The gate's job is the exit code.
|
|
15
|
+
* A read-only checkout, a full disk or a directory somebody's CI cannot create
|
|
16
|
+
* must not turn a passing build red on account of bookkeeping — the failure is
|
|
17
|
+
* reported and the gate's own verdict stands.
|
|
18
|
+
*
|
|
19
|
+
* **A line that will not parse is counted and skipped**, exactly as in the
|
|
20
|
+
* store. Losing the whole history because one line is broken would be the
|
|
21
|
+
* worst possible response; pretending the history is complete would be the
|
|
22
|
+
* second worst.
|
|
23
|
+
*/
|
|
24
|
+
import { mkdir, readFile, writeFile } from 'node:fs/promises';
|
|
25
|
+
import { join } from 'node:path';
|
|
26
|
+
import { isWaiverUse } from '@trazum/core';
|
|
27
|
+
/** One file, not one per month: a waiver history is small and read whole. */
|
|
28
|
+
export const WAIVER_LOG = '.trazum/waivers.jsonl';
|
|
29
|
+
export async function readWaiverLog(root) {
|
|
30
|
+
let raw;
|
|
31
|
+
try {
|
|
32
|
+
raw = await readFile(join(root, WAIVER_LOG), 'utf8');
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Absent is the normal state of a repository that has never waived
|
|
36
|
+
// anything, and it is not an error.
|
|
37
|
+
return { uses: [], unreadable: [], present: false };
|
|
38
|
+
}
|
|
39
|
+
const uses = [];
|
|
40
|
+
const unreadable = [];
|
|
41
|
+
raw.split('\n').forEach((line, index) => {
|
|
42
|
+
if (line.trim() === '')
|
|
43
|
+
return;
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(line);
|
|
46
|
+
if (isWaiverUse(parsed))
|
|
47
|
+
uses.push(parsed);
|
|
48
|
+
else
|
|
49
|
+
unreadable.push(index + 1);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
unreadable.push(index + 1);
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
return { uses, unreadable, present: true };
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Appends one use, and swallows any failure after reporting it.
|
|
59
|
+
*
|
|
60
|
+
* Returns the error message rather than throwing, so the caller can print it
|
|
61
|
+
* beside the gate's own output without the gate ever depending on the write.
|
|
62
|
+
*/
|
|
63
|
+
export async function appendWaiverUse(root, use) {
|
|
64
|
+
const path = join(root, WAIVER_LOG);
|
|
65
|
+
try {
|
|
66
|
+
await mkdir(join(path, '..'), { recursive: true });
|
|
67
|
+
await writeFile(path, `${JSON.stringify(use)}\n`, { flag: 'a', mode: 0o600 });
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
return error instanceof Error ? error.message : String(error);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=waiver-log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"waiver-log.js","sourceRoot":"","sources":["../src/waiver-log.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAG3C,6EAA6E;AAC7E,MAAM,CAAC,MAAM,UAAU,GAAG,uBAAuB,CAAC;AAUlD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAY;IAC9C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,EAAE,MAAM,CAAC,CAAC;IACvD,CAAC;IAAC,MAAM,CAAC;QACP,mEAAmE;QACnE,oCAAoC;QACpC,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,UAAU,EAAE,EAAE,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACtD,CAAC;IAED,MAAM,IAAI,GAAgB,EAAE,CAAC;IAC7B,MAAM,UAAU,GAAa,EAAE,CAAC;IAChC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;QACtC,IAAI,IAAI,CAAC,IAAI,EAAE,KAAK,EAAE;YAAE,OAAO;QAC/B,IAAI,CAAC;YACH,MAAM,MAAM,GAAY,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACzC,IAAI,WAAW,CAAC,MAAM,CAAC;gBAAE,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;;gBACtC,UAAU,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAClC,CAAC;QAAC,MAAM,CAAC;YACP,UAAU,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC;QAC7B,CAAC;IACH,CAAC,CAAC,CAAC;IACH,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,IAAY,EAAE,GAAc;IAChE,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,UAAU,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QACnD,MAAM,SAAS,CAAC,IAAI,EAAE,GAAG,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,IAAI,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;QAC9E,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAChE,CAAC;AACH,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trazum/cli",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.49.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.
|
|
40
|
+
"@trazum/core": "1.49.0"
|
|
41
41
|
},
|
|
42
42
|
"devDependencies": {
|
|
43
43
|
"@types/node": "^26.2.0",
|
package/src/i18n/en.ts
CHANGED
|
@@ -1554,6 +1554,8 @@ ${bold('EXAMPLES')}
|
|
|
1554
1554
|
`WAIVED — the ${gate} failure above is on the record and silenced until ${until} (${daysLeft} days left): "${reason}". The bill still counts it; only the exit code is quiet, and the day the waiver expires this gate fails again.`,
|
|
1555
1555
|
waiveExpired: (gate, until, reason) =>
|
|
1556
1556
|
`The waiver on ${gate} expired on ${until} and no longer silences anything. It was written for: "${reason}". Renew it with a new date and a current reason, or fix what it was covering — an expired waiver left in place is a finding deleted with extra steps.`,
|
|
1557
|
+
waiveNotRecorded: (path, because) =>
|
|
1558
|
+
` (This waiver was not written to ${path}: ${because}. The gate's verdict above is unaffected.)`,
|
|
1557
1559
|
summaryNoComparison: () =>
|
|
1558
1560
|
'No previous log was given, so nothing here says whether the bill moved — a summary without a comparison states the bill, not its stability.',
|
|
1559
1561
|
summaryFooter: () =>
|
|
@@ -1664,7 +1666,9 @@ ${bold('EXAMPLES')}
|
|
|
1664
1666
|
nothingMeasured: (dir) =>
|
|
1665
1667
|
`Nothing is measured yet (the store at ${dir} is empty), so the budget half of every answer will say so. The cost half still answers from the catalogue: offline is a mode, not a failure.`,
|
|
1666
1668
|
noBudget: () =>
|
|
1667
|
-
'No spend.
|
|
1669
|
+
'No spend.monthlyUsd is configured, so "is there budget left" has no subject and every answer says so rather than guessing one. spend.maxUsd is deliberately not read here: it gates whatever period a log covers, and reading it as a monthly limit is how two surfaces of this tool come to disagree.',
|
|
1670
|
+
partialCoverage: (measuredDays, elapsedDays, period) =>
|
|
1671
|
+
`Only ${measuredDays} of the ${elapsedDays} elapsed days of ${period} carry any measurement, so the consumed figure is a floor on the period rather than the period. Pull the missing days with trazum connect before treating what is left as headroom.`,
|
|
1668
1672
|
badPort: (value) => `"${value}" is not a port. Give a whole number from 0 to 65535, or use --socket.`,
|
|
1669
1673
|
},
|
|
1670
1674
|
|
|
@@ -1740,6 +1744,27 @@ ${bold('EXAMPLES')}
|
|
|
1740
1744
|
span === null
|
|
1741
1745
|
? `Nothing was older than ${days} days. ${kept} measurements kept, and the append log compacted.`
|
|
1742
1746
|
: `Deleted ${count} measurements older than ${days} days, covering ${span} and ${usd} of measured spend. ${kept} kept, and the append log compacted to what the store already resolved to.`,
|
|
1747
|
+
budgetHeading: (period) => `Budget for ${period}`,
|
|
1748
|
+
budgetStanding: (consumed, limit, share, measuredDays, periodDays) =>
|
|
1749
|
+
`${consumed} of ${limit} (${share}), measured over ${measuredDays} of the month's ${periodDays} days.`,
|
|
1750
|
+
budgetShape: (shape, elapsedPct, coverage) =>
|
|
1751
|
+
shape === 'ahead'
|
|
1752
|
+
? `The money is going faster than the calendar: ${elapsedPct}% of the month has elapsed.`
|
|
1753
|
+
: shape === 'behind'
|
|
1754
|
+
? `The money is going slower than the calendar: ${elapsedPct}% of the month has elapsed.`
|
|
1755
|
+
: shape === 'on-pace'
|
|
1756
|
+
? `Tracking the calendar: ${elapsedPct}% of the month has elapsed.`
|
|
1757
|
+
: coverage === 'partial'
|
|
1758
|
+
? 'Whether that is fast or slow for the month cannot be told from a floor: the unmeasured days spent something, and only an overrun would be unarguable.'
|
|
1759
|
+
: 'There is nothing to compare the spend against yet.',
|
|
1760
|
+
budgetNeverForecast: () =>
|
|
1761
|
+
'That is a shape, not a forecast. Where this goes next depends on what you do next, and no arithmetic here knows that.',
|
|
1762
|
+
budgetNothingMeasured: (elapsedDays) =>
|
|
1763
|
+
`Nothing has been measured this month, across ${elapsedDays} elapsed ${elapsedDays === 1 ? 'day' : 'days'}. That is not a budget under control — it is a budget nobody is watching. Run trazum connect to pull what the provider has.`,
|
|
1764
|
+
budgetPartial: (measuredDays, elapsedDays, days) =>
|
|
1765
|
+
`Only ${measuredDays} of ${elapsedDays} elapsed days carry any measurement, so the figure below is a floor on the month rather than the month. Missing: ${days}.`,
|
|
1766
|
+
budgetScopesUnmeasured: (count) =>
|
|
1767
|
+
`${count} budgeted ${count === 1 ? 'scope' : 'scopes'} (per label or per service) cannot be answered from the store: a store record carries a provider and a model, not a workload label. Gate those with trazum profile against a per-call log.`,
|
|
1743
1768
|
},
|
|
1744
1769
|
|
|
1745
1770
|
connect: {
|
|
@@ -1807,6 +1832,33 @@ ${bold('EXAMPLES')}
|
|
|
1807
1832
|
unrecognized: (name) => `${name} is neither a stored report nor a saved plan, so it is in no series above.`,
|
|
1808
1833
|
footer: () =>
|
|
1809
1834
|
'A series names shapes, not futures. Twenty points make a trend visible; they do not make next month knowable — where these lines go next is yours to judge.',
|
|
1835
|
+
waiverHeading: () => 'What this repository has been living with',
|
|
1836
|
+
waiverSince: (day, uses) =>
|
|
1837
|
+
`${uses} recorded ${uses === 1 ? 'use' : 'uses'} since ${day}, when recording started.`,
|
|
1838
|
+
waiverNoneRecorded: () =>
|
|
1839
|
+
'No waiver has silenced a gate since recording started. Nothing here is inferred from the config — a waiver written down and never hit is not a decision anyone is living with.',
|
|
1840
|
+
waiverHabit: (gate, uses, days, firstDay, lastDay) =>
|
|
1841
|
+
`${gate}: ${uses} ${uses === 1 ? 'use' : 'uses'} across ${days} ${days === 1 ? 'day' : 'days'}, ${firstDay} to ${lastDay}`,
|
|
1842
|
+
waiverVerdict: (verdict) =>
|
|
1843
|
+
verdict === 'used-once'
|
|
1844
|
+
? 'Used once. Nothing to read into it yet.'
|
|
1845
|
+
: verdict === 'recurring'
|
|
1846
|
+
? 'The same decision, holding. The gate keeps firing and the reason has not moved.'
|
|
1847
|
+
: verdict === 'renewed-without-revisiting'
|
|
1848
|
+
? 'The expiry has moved and the reason has not. That is the shape a decision takes when nobody is revisiting it — which is sometimes exactly right, and worth saying out loud either way.'
|
|
1849
|
+
: 'The reason changed between uses. Somebody looked again.',
|
|
1850
|
+
waiverReasonNow: (reason) => `Reason: ${reason}`,
|
|
1851
|
+
waiverReasonsChanged: (count) => `${count} different reasons given over that time.`,
|
|
1852
|
+
waiverExpiriesMoved: (from, to, count) =>
|
|
1853
|
+
`Expiry moved ${count} ${count === 1 ? 'time' : 'times'}: ${from} → ${to}.`,
|
|
1854
|
+
waiverNoLongerConfigured: () =>
|
|
1855
|
+
'Not in the config any more. The decision was reversed; the record keeps it.',
|
|
1856
|
+
waiverNeverUsed: (gates) =>
|
|
1857
|
+
`Waived in the config and never hit by a recorded run: ${gates}. Either the gate stopped failing — good news nobody wrote down — or the waiver names a situation that does not arise. Both are worth deleting.`,
|
|
1858
|
+
waiverUnreadable: (count, path) =>
|
|
1859
|
+
`${count} ${count === 1 ? 'line' : 'lines'} in ${path} could not be read and are not counted above.`,
|
|
1860
|
+
waiverStartsHere: () =>
|
|
1861
|
+
'Nothing before that day exists. This record began when recording did, and no past was reconstructed from the config as it stands.',
|
|
1810
1862
|
},
|
|
1811
1863
|
|
|
1812
1864
|
verify: {
|
package/src/i18n/es.ts
CHANGED
|
@@ -1584,6 +1584,8 @@ ${bold('EJEMPLOS')}
|
|
|
1584
1584
|
`WAIVED — el fallo de ${gate} de arriba queda registrado y silenciado hasta ${until} (${daysLeft} días restantes): "${reason}". La factura lo sigue contando; solo el código de salida calla, y el día que caduque el waiver este gate vuelve a fallar.`,
|
|
1585
1585
|
waiveExpired: (gate, until, reason) =>
|
|
1586
1586
|
`El waiver de ${gate} caducó el ${until} y ya no silencia nada. Se escribió por: "${reason}". Renuévalo con fecha nueva y razón vigente, o arregla lo que cubría — un waiver caducado dejado ahí es un hallazgo borrado con pasos extra.`,
|
|
1587
|
+
waiveNotRecorded: (path, because) =>
|
|
1588
|
+
` (Este waiver no se pudo escribir en ${path}: ${because}. El veredicto de la puerta de arriba no cambia.)`,
|
|
1587
1589
|
summaryNoComparison: () =>
|
|
1588
1590
|
'No se dio un registro anterior, así que nada de aquí dice si la factura se movió — un resumen sin comparación indica la factura, no su estabilidad.',
|
|
1589
1591
|
summaryFooter: () =>
|
|
@@ -1694,7 +1696,9 @@ ${bold('EJEMPLOS')}
|
|
|
1694
1696
|
nothingMeasured: (dir) =>
|
|
1695
1697
|
`Todavía no hay nada medido (el almacén de ${dir} está vacío), así que la mitad de presupuesto de cada respuesta lo dirá. La mitad del coste sigue respondiendo desde el catálogo: sin conexión es un modo, no un fallo.`,
|
|
1696
1698
|
noBudget: () =>
|
|
1697
|
-
'No hay spend.
|
|
1699
|
+
'No hay spend.monthlyUsd configurado, así que "queda presupuesto" no tiene sujeto y cada respuesta lo dice en vez de inventarse uno. spend.maxUsd no se lee aquí a propósito: ese controla el periodo que cubra un registro, y leerlo como límite mensual es justo como dos superficies de esta herramienta acaban en desacuerdo.',
|
|
1700
|
+
partialCoverage: (measuredDays, elapsedDays, period) =>
|
|
1701
|
+
`Solo ${measuredDays} de los ${elapsedDays} días transcurridos de ${period} tienen alguna medición, así que la cifra consumida es un suelo del periodo y no el periodo. Descarga los días que faltan con trazum connect antes de tratar lo que queda como margen.`,
|
|
1698
1702
|
badPort: (value) => `"${value}" no es un puerto. Da un número entero de 0 a 65535, o usa --socket.`,
|
|
1699
1703
|
},
|
|
1700
1704
|
|
|
@@ -1770,6 +1774,27 @@ ${bold('EJEMPLOS')}
|
|
|
1770
1774
|
span === null
|
|
1771
1775
|
? `Nada era más antiguo que ${days} días. ${kept} mediciones conservadas, y el log compactado.`
|
|
1772
1776
|
: `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.`,
|
|
1777
|
+
budgetHeading: (period) => `Presupuesto de ${period}`,
|
|
1778
|
+
budgetStanding: (consumed, limit, share, measuredDays, periodDays) =>
|
|
1779
|
+
`${consumed} de ${limit} (${share}), medido sobre ${measuredDays} de los ${periodDays} días del mes.`,
|
|
1780
|
+
budgetShape: (shape, elapsedPct, coverage) =>
|
|
1781
|
+
shape === 'ahead'
|
|
1782
|
+
? `El dinero va más rápido que el calendario: ha transcurrido el ${elapsedPct}% del mes.`
|
|
1783
|
+
: shape === 'behind'
|
|
1784
|
+
? `El dinero va más lento que el calendario: ha transcurrido el ${elapsedPct}% del mes.`
|
|
1785
|
+
: shape === 'on-pace'
|
|
1786
|
+
? `Al ritmo del calendario: ha transcurrido el ${elapsedPct}% del mes.`
|
|
1787
|
+
: coverage === 'partial'
|
|
1788
|
+
? 'Si eso es rápido o lento para el mes no se puede saber desde un suelo: los días sin medir gastaron algo, y solo un exceso sería incontestable.'
|
|
1789
|
+
: 'Todavía no hay nada con lo que comparar el gasto.',
|
|
1790
|
+
budgetNeverForecast: () =>
|
|
1791
|
+
'Eso es una forma, no un pronóstico. A dónde va esto después depende de lo que hagas después, y ninguna aritmética de aquí lo sabe.',
|
|
1792
|
+
budgetNothingMeasured: (elapsedDays) =>
|
|
1793
|
+
`No se ha medido nada este mes, en ${elapsedDays} ${elapsedDays === 1 ? 'día transcurrido' : 'días transcurridos'}. Eso no es un presupuesto bajo control — es un presupuesto que nadie está mirando. Ejecuta trazum connect para descargar lo que tenga el proveedor.`,
|
|
1794
|
+
budgetPartial: (measuredDays, elapsedDays, days) =>
|
|
1795
|
+
`Solo ${measuredDays} de ${elapsedDays} días transcurridos tienen alguna medición, así que la cifra de abajo es un suelo del mes y no el mes. Faltan: ${days}.`,
|
|
1796
|
+
budgetScopesUnmeasured: (count) =>
|
|
1797
|
+
`${count} ${count === 1 ? 'ámbito presupuestado' : 'ámbitos presupuestados'} (por etiqueta o por servicio) no se pueden responder desde el almacén: un registro del almacén lleva un proveedor y un modelo, no una etiqueta de flujo. Contrólalos con trazum profile contra un registro por llamada.`,
|
|
1773
1798
|
},
|
|
1774
1799
|
|
|
1775
1800
|
connect: {
|
|
@@ -1837,6 +1862,33 @@ ${bold('EJEMPLOS')}
|
|
|
1837
1862
|
unrecognized: (name) => `${name} no es ni un informe guardado ni un plan guardado, así que no está en ninguna serie de arriba.`,
|
|
1838
1863
|
footer: () =>
|
|
1839
1864
|
'Una serie nombra formas, no futuros. Veinte puntos hacen visible una tendencia; no hacen conocible el mes que viene — adónde van estas líneas después lo juzgas tú.',
|
|
1865
|
+
waiverHeading: () => 'Con lo que este repositorio ha estado conviviendo',
|
|
1866
|
+
waiverSince: (day, uses) =>
|
|
1867
|
+
`${uses} ${uses === 1 ? 'uso registrado' : 'usos registrados'} desde el ${day}, cuando empezó el registro.`,
|
|
1868
|
+
waiverNoneRecorded: () =>
|
|
1869
|
+
'Ningún waiver ha silenciado una puerta desde que empezó el registro. Nada de aquí se deduce de la configuración — un waiver escrito y nunca usado no es una decisión con la que nadie conviva.',
|
|
1870
|
+
waiverHabit: (gate, uses, days, firstDay, lastDay) =>
|
|
1871
|
+
`${gate}: ${uses} ${uses === 1 ? 'uso' : 'usos'} en ${days} ${days === 1 ? 'día' : 'días'}, del ${firstDay} al ${lastDay}`,
|
|
1872
|
+
waiverVerdict: (verdict) =>
|
|
1873
|
+
verdict === 'used-once'
|
|
1874
|
+
? 'Usado una vez. Todavía no hay nada que leer en ello.'
|
|
1875
|
+
: verdict === 'recurring'
|
|
1876
|
+
? 'La misma decisión, sosteniéndose. La puerta sigue saltando y el motivo no ha cambiado.'
|
|
1877
|
+
: verdict === 'renewed-without-revisiting'
|
|
1878
|
+
? 'La fecha de caducidad se ha movido y el motivo no. Esa es la forma que toma una decisión que nadie está revisando — a veces es exactamente lo correcto, y merece decirse en voz alta igualmente.'
|
|
1879
|
+
: 'El motivo cambió entre usos. Alguien volvió a mirarlo.',
|
|
1880
|
+
waiverReasonNow: (reason) => `Motivo: ${reason}`,
|
|
1881
|
+
waiverReasonsChanged: (count) => `${count} motivos distintos dados en ese tiempo.`,
|
|
1882
|
+
waiverExpiriesMoved: (from, to, count) =>
|
|
1883
|
+
`La caducidad se movió ${count} ${count === 1 ? 'vez' : 'veces'}: ${from} → ${to}.`,
|
|
1884
|
+
waiverNoLongerConfigured: () =>
|
|
1885
|
+
'Ya no está en la configuración. La decisión se revirtió; el registro la conserva.',
|
|
1886
|
+
waiverNeverUsed: (gates) =>
|
|
1887
|
+
`Con waiver en la configuración y nunca usados por una ejecución registrada: ${gates}. O la puerta dejó de fallar — buenas noticias que nadie anotó — o el waiver nombra una situación que no ocurre. Ambos merecen borrarse.`,
|
|
1888
|
+
waiverUnreadable: (count, path) =>
|
|
1889
|
+
`${count} ${count === 1 ? 'línea' : 'líneas'} de ${path} no se pudieron leer y no cuentan arriba.`,
|
|
1890
|
+
waiverStartsHere: () =>
|
|
1891
|
+
'Nada anterior a ese día existe. Este registro empezó cuando empezó a registrarse, y no se reconstruyó ningún pasado a partir de la configuración actual.',
|
|
1840
1892
|
},
|
|
1841
1893
|
|
|
1842
1894
|
verify: {
|
package/src/i18n/types.ts
CHANGED
|
@@ -877,6 +877,14 @@ export interface CliMessages {
|
|
|
877
877
|
*/
|
|
878
878
|
waiveActive(gate: string, reason: string, until: string, daysLeft: string): string;
|
|
879
879
|
waiveExpired(gate: string, until: string, reason: string): string;
|
|
880
|
+
/**
|
|
881
|
+
* A use that could not be written down.
|
|
882
|
+
*
|
|
883
|
+
* Printed dim and never as an error: the gate's verdict is unaffected, and
|
|
884
|
+
* a read-only checkout must not turn a passing build red on account of
|
|
885
|
+
* bookkeeping.
|
|
886
|
+
*/
|
|
887
|
+
waiveNotRecorded(path: string, because: string): string;
|
|
880
888
|
/**
|
|
881
889
|
* `--markdown-summary`: the short form for a pull-request body or a weekly
|
|
882
890
|
* note. A view over the same report, never a different set of figures.
|
|
@@ -1143,6 +1151,12 @@ export interface CliMessages {
|
|
|
1143
1151
|
measuredFrom(usd: string): string;
|
|
1144
1152
|
nothingMeasured(dir: string): string;
|
|
1145
1153
|
noBudget(): string;
|
|
1154
|
+
/**
|
|
1155
|
+
* The period is only partly measured — said out loud, because a position
|
|
1156
|
+
* standing on three days out of thirty must not read as a comfortable
|
|
1157
|
+
* ninety per cent remaining.
|
|
1158
|
+
*/
|
|
1159
|
+
partialCoverage(measuredDays: number, elapsedDays: number, period: string): string;
|
|
1146
1160
|
badPort(value: string): string;
|
|
1147
1161
|
};
|
|
1148
1162
|
|
|
@@ -1197,6 +1211,15 @@ export interface CliMessages {
|
|
|
1197
1211
|
pruneNeedsPolicy(): string;
|
|
1198
1212
|
pruneDryRun(count: string, days: string, span: string | null, usd: string): string;
|
|
1199
1213
|
pruned(count: string, days: string, span: string | null, usd: string, kept: string): string;
|
|
1214
|
+
/** The live budget — the one number `serve` and the MCP guard also read. */
|
|
1215
|
+
budgetHeading(period: string): string;
|
|
1216
|
+
budgetStanding(consumed: string, limit: string, share: string, measuredDays: string, periodDays: string): string;
|
|
1217
|
+
/** The shape of the burn, named. Never a date — see `budgetNeverForecast`. */
|
|
1218
|
+
budgetShape(shape: string, elapsedPct: number, coverage: string): string;
|
|
1219
|
+
budgetNeverForecast(): string;
|
|
1220
|
+
budgetNothingMeasured(elapsedDays: number): string;
|
|
1221
|
+
budgetPartial(measuredDays: number, elapsedDays: number, days: string): string;
|
|
1222
|
+
budgetScopesUnmeasured(count: number): string;
|
|
1200
1223
|
};
|
|
1201
1224
|
|
|
1202
1225
|
/**
|
|
@@ -1254,6 +1277,19 @@ export interface CliMessages {
|
|
|
1254
1277
|
undated(name: string): string;
|
|
1255
1278
|
unrecognized(name: string): string;
|
|
1256
1279
|
footer(): string;
|
|
1280
|
+
/** The waiver record — what this team has been living with, and for how long. */
|
|
1281
|
+
waiverHeading(): string;
|
|
1282
|
+
waiverSince(day: string, uses: number): string;
|
|
1283
|
+
waiverNoneRecorded(): string;
|
|
1284
|
+
waiverHabit(gate: string, uses: number, days: number, firstDay: string, lastDay: string): string;
|
|
1285
|
+
waiverVerdict(verdict: string): string;
|
|
1286
|
+
waiverReasonNow(reason: string): string;
|
|
1287
|
+
waiverReasonsChanged(count: number): string;
|
|
1288
|
+
waiverExpiriesMoved(from: string, to: string, count: number): string;
|
|
1289
|
+
waiverNoLongerConfigured(): string;
|
|
1290
|
+
waiverNeverUsed(gates: string): string;
|
|
1291
|
+
waiverUnreadable(count: number, path: string): string;
|
|
1292
|
+
waiverStartsHere(): string;
|
|
1257
1293
|
};
|
|
1258
1294
|
|
|
1259
1295
|
/**
|