@trazum/cli 1.33.0 → 1.35.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 +9 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +10 -0
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/types.d.ts +13 -0
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.js +55 -8
- package/dist/index.js.map +1 -1
- package/dist/markdown.d.ts +14 -0
- package/dist/markdown.d.ts.map +1 -1
- package/dist/markdown.js +55 -1
- package/dist/markdown.js.map +1 -1
- package/package.json +2 -2
- package/src/i18n/en.ts +13 -0
- package/src/i18n/es.ts +14 -0
- package/src/i18n/types.ts +13 -0
- package/src/index.ts +53 -8
- package/src/markdown.ts +94 -1
package/dist/index.js
CHANGED
|
@@ -259,7 +259,7 @@ const COMMAND_FLAGS = {
|
|
|
259
259
|
],
|
|
260
260
|
check: ['max-tokens', 'level', 'exact-tokens', 'markdown-out', 'baseline'],
|
|
261
261
|
baseline: ['model', 'calls', 'output-tokens', 'cache-hit-rate', 'batch', 'exact-tokens', 'out', 'o'],
|
|
262
|
-
profile: ['json', 'pricing', 'pricing-live', 'against', 'what-if', 'markdown-out', 'csv-out', 'csv-shape', 'max-usd', 'max-growth-usd', 'max-cache-loss-usd', 'max-day-usd', 'max-session-usd', 'label', 'since', 'until', 'dry-run'],
|
|
262
|
+
profile: ['json', 'pricing', 'pricing-live', 'against', 'what-if', 'markdown-out', 'csv-out', 'csv-shape', 'max-usd', 'max-growth-usd', 'max-cache-loss-usd', 'max-day-usd', 'max-session-usd', 'label', 'since', 'until', 'dry-run', 'markdown-summary'],
|
|
263
263
|
route: ['prompt-file', 'cases', 'label', 'concurrency', 'json', 'yes', 'pricing', 'pricing-live'],
|
|
264
264
|
eval: ['cases', 'level', 'concurrency', 'export', 'out', 'o', 'model'],
|
|
265
265
|
prune: ['cases', 'concurrency', 'json', 'yes'],
|
|
@@ -1778,6 +1778,41 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
1778
1778
|
*/
|
|
1779
1779
|
const gateVerdicts = [];
|
|
1780
1780
|
let gateFailed = false;
|
|
1781
|
+
/**
|
|
1782
|
+
* Findings as policy. A waiver silences one gate's exit code for a bounded
|
|
1783
|
+
* time, on the record: the failure still prints (waived is shown as
|
|
1784
|
+
* waived, never hidden — the bill still counts it), the reason and the
|
|
1785
|
+
* days left print beside it, and the day the waiver expires the gate
|
|
1786
|
+
* fails again louder, naming the date and the reason somebody wrote.
|
|
1787
|
+
* That expiry is the entire mechanism by which a waiver stays a decision
|
|
1788
|
+
* instead of becoming a habit.
|
|
1789
|
+
*/
|
|
1790
|
+
const waiverFor = (gate) => {
|
|
1791
|
+
const entry = (config.waive ?? []).find((w) => w.gate === gate);
|
|
1792
|
+
if (entry === undefined)
|
|
1793
|
+
return null;
|
|
1794
|
+
// The waiver covers its named day whole: expiry begins the next UTC day.
|
|
1795
|
+
const expiresMs = Date.parse(`${entry.until}T00:00:00Z`) + 86_400_000;
|
|
1796
|
+
return { entry, expired: Date.now() >= expiresMs };
|
|
1797
|
+
};
|
|
1798
|
+
/**
|
|
1799
|
+
* Applies a waiver to one failing gate. Returns true when the failure is
|
|
1800
|
+
* silenced — the caller skips its exitCode — and prints the record either
|
|
1801
|
+
* way, because a waived failure that vanished from the output would be a
|
|
1802
|
+
* finding deleted with extra steps.
|
|
1803
|
+
*/
|
|
1804
|
+
const waived = (gate) => {
|
|
1805
|
+
const found = waiverFor(gate);
|
|
1806
|
+
if (found === null)
|
|
1807
|
+
return false;
|
|
1808
|
+
if (found.expired) {
|
|
1809
|
+
console.error(c.red(t.profile.waiveExpired(gate, found.entry.until, found.entry.reason)));
|
|
1810
|
+
return false;
|
|
1811
|
+
}
|
|
1812
|
+
const daysLeft = Math.max(0, Math.ceil((Date.parse(`${found.entry.until}T00:00:00Z`) + 86_400_000 - Date.now()) / 86_400_000));
|
|
1813
|
+
console.error(c.yellow(t.profile.waiveActive(gate, found.entry.reason, found.entry.until, String(daysLeft))));
|
|
1814
|
+
return true;
|
|
1815
|
+
};
|
|
1781
1816
|
const applyGates = () => {
|
|
1782
1817
|
/**
|
|
1783
1818
|
* Before any verdict: whether the gated figure is the whole bill. A gate
|
|
@@ -1825,7 +1860,8 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
1825
1860
|
}
|
|
1826
1861
|
if (usd > limit) {
|
|
1827
1862
|
console.error(c.red(t.profile.labelBudgetFailed(label, formatUsd(usd), formatUsd(limit))));
|
|
1828
|
-
|
|
1863
|
+
if (!waived(`byLabel:${label}`))
|
|
1864
|
+
process.exitCode = 1;
|
|
1829
1865
|
}
|
|
1830
1866
|
else {
|
|
1831
1867
|
console.error(c.dim(t.profile.labelBudgetOk(label, formatUsd(usd), formatUsd(limit))));
|
|
@@ -1886,7 +1922,8 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
1886
1922
|
* copy says so.
|
|
1887
1923
|
*/
|
|
1888
1924
|
explainFailure(report.total.totalUsd - maxUsd);
|
|
1889
|
-
|
|
1925
|
+
if (!waived('maxUsd'))
|
|
1926
|
+
process.exitCode = 1;
|
|
1890
1927
|
}
|
|
1891
1928
|
else {
|
|
1892
1929
|
console.error(c.dim(t.profile.maxUsdOk(formatUsd(report.total.totalUsd), formatUsd(maxUsd))));
|
|
@@ -1913,11 +1950,15 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
1913
1950
|
const worst = blinded[0];
|
|
1914
1951
|
if (worst !== undefined) {
|
|
1915
1952
|
console.error(c.red(t.profile.maxGrowthCoverageLost(blinded.map((d) => t.profile.coverageField(d.field)).join(', '), pct(worst.was), pct(worst.now))));
|
|
1953
|
+
// Deliberately unwaivable: this failure is "the comparison cannot
|
|
1954
|
+
// be made", and a waiver on unmeasurability would be a decision to
|
|
1955
|
+
// stop measuring — not a budget decision with an end date.
|
|
1916
1956
|
process.exitCode = 1;
|
|
1917
1957
|
}
|
|
1918
1958
|
else if (againstDelta > maxGrowth) {
|
|
1919
1959
|
console.error(c.red(t.profile.maxGrowthUsdFailed(formatSignedUsd(againstDelta), formatUsd(maxGrowth))));
|
|
1920
|
-
|
|
1960
|
+
if (!waived('maxGrowthUsd'))
|
|
1961
|
+
process.exitCode = 1;
|
|
1921
1962
|
}
|
|
1922
1963
|
}
|
|
1923
1964
|
/**
|
|
@@ -1933,11 +1974,13 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
1933
1974
|
const gateCache = cacheEconomics(report.total);
|
|
1934
1975
|
if (gateCache.deltaUsd > maxLoss) {
|
|
1935
1976
|
console.error(c.red(t.profile.maxCacheLossFailed(formatUsd(gateCache.deltaUsd), formatUsd(maxLoss))));
|
|
1936
|
-
|
|
1977
|
+
if (!waived('maxCacheLossUsd'))
|
|
1978
|
+
process.exitCode = 1;
|
|
1937
1979
|
}
|
|
1938
1980
|
else if (gateCache.worstCaseDeltaUsd > maxLoss) {
|
|
1939
1981
|
console.error(c.red(t.profile.maxCacheLossWorstCase(report.total.assumedWriteTtlCalls, formatUsd(gateCache.worstCaseDeltaUsd), formatUsd(maxLoss))));
|
|
1940
|
-
|
|
1982
|
+
if (!waived('maxCacheLossUsd'))
|
|
1983
|
+
process.exitCode = 1;
|
|
1941
1984
|
}
|
|
1942
1985
|
else {
|
|
1943
1986
|
console.error(c.dim(t.profile.maxCacheLossOk(formatUsd(Math.max(0, gateCache.worstCaseDeltaUsd)), formatUsd(maxLoss))));
|
|
@@ -1982,7 +2025,8 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
1982
2025
|
if (worst.usd > maxDay) {
|
|
1983
2026
|
console.error(c.red(`${t.profile.maxDayFailed(worst.day, formatUsd(worst.usd), formatUsd(maxDay))}${suspect}`));
|
|
1984
2027
|
explainFailure(worst.usd - maxDay, { namesLargest: true });
|
|
1985
|
-
|
|
2028
|
+
if (!waived('maxDayUsd'))
|
|
2029
|
+
process.exitCode = 1;
|
|
1986
2030
|
}
|
|
1987
2031
|
else {
|
|
1988
2032
|
console.error(c.dim(t.profile.maxDayOk(worst.day, formatUsd(worst.usd), formatUsd(maxDay))));
|
|
@@ -2023,7 +2067,8 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
2023
2067
|
else if (report.sessionSpend.maxUsd > maxSession) {
|
|
2024
2068
|
console.error(c.red(t.profile.maxSessionFailed(formatUsd(report.sessionSpend.maxUsd), formatUsd(maxSession), n(report.sessionSpend.sessions))));
|
|
2025
2069
|
explainFailure(report.sessionSpend.maxUsd - maxSession);
|
|
2026
|
-
|
|
2070
|
+
if (!waived('maxSessionUsd'))
|
|
2071
|
+
process.exitCode = 1;
|
|
2027
2072
|
}
|
|
2028
2073
|
else {
|
|
2029
2074
|
console.error(c.dim(t.profile.maxSessionOk(formatUsd(report.sessionSpend.maxUsd), formatUsd(maxSession), n(report.sessionSpend.sessions))));
|
|
@@ -2091,6 +2136,8 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
2091
2136
|
// The verdict, where the person reading CI will see it. recordGates()
|
|
2092
2137
|
// runs before the side files for exactly this.
|
|
2093
2138
|
...(gateVerdicts.length > 0 ? { gates: { failed: gateFailed, lines: gateVerdicts } } : {}),
|
|
2139
|
+
// The short form, for a reader who is not in the terminal.
|
|
2140
|
+
...(boolFlag(args, 'markdown-summary') ? { summary: true } : {}),
|
|
2094
2141
|
// The repricing, when --what-if was given: computed once above and
|
|
2095
2142
|
// handed over, so the summary in a pull request cannot disagree
|
|
2096
2143
|
// with the terminal about what a move would cost.
|