@trazum/cli 1.46.0 → 1.48.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 +29 -1
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +29 -1
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/types.d.ts +43 -1
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.js +146 -24
- 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 +41 -2
- package/src/i18n/es.ts +41 -2
- package/src/i18n/types.ts +37 -1
- package/src/index.ts +157 -21
- package/src/waiver-log.ts +81 -0
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { open, readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
3
3
|
import { join, resolve as resolvePath } from 'node:path';
|
|
4
4
|
import { gunzipSync } from 'node:zlib';
|
|
5
|
-
import { applyRewrites, BASELINE_FILENAME, BASELINE_VERSION, breaches, cacheableMinimum, analyzeCachePrefix, billLevers, bucketedCacheEconomics, bucketedProfile, buildHistory, buildPlan, connectorFor, CONNECTORS, normalizeAnthropicUsage, normalizeOpenAIUsage, bucketsFromRecords, evaluateWatch, firedKey, pruneRecords, recordsFromBuckets, storeInventory, storedReportFrom, verifyPlan, cacheEconomics, cacheHitRate, contextPressure, comparePrompts, compareToBaseline, computeSavings, countTokensAnthropic, DEFAULT_USAGE, detectFromSource, matchLocale, proposeInit, MIN_RATE_DAYS, parseConfig, coverageDrift, driversBetween, explainGateFailure, assignSources, fleetRollup, labelCoverage, measuredUsage, gateMargin, GATE_MARGIN_TIGHT, estimateTokens, evaluate, extractPrompts, findExamples, formatBaseline, formatSignedUsd, formatUsd, getMessages, getModel, hasMarker, LOCALES, MAX_BASELINE_BYTES, moneyIsComparable, mostSpecificMatch, nearestName, optimize, parseBaseline, PHRASE_LANGUAGES, plannedCalls, profilePrompt, profileToCsv, profileUsage, promptId, providerFromEnv, pruneExamples, refineWithLlm, rejectionText, reorderForCache, repriceProfile, reviewAgeDays, reviewExamples, RULES, sharedPrefixes, sharesOf, SOURCE_EXTENSIONS, suggestRewrites, toOtlpMetrics, toPromptfoo, TTL_1H_MS, UNLABELLED, withExactTokenCounts, } from '@trazum/core';
|
|
5
|
+
import { applyRewrites, BASELINE_FILENAME, BASELINE_VERSION, breaches, cacheableMinimum, analyzeCachePrefix, billLevers, bucketedCacheEconomics, bucketedProfile, buildHistory, buildPlan, connectorFor, CONNECTORS, normalizeAnthropicUsage, normalizeOpenAIUsage, bucketsFromRecords, evaluateWatch, firedKey, pruneRecords, recordsFromBuckets, storeInventory, storedReportFrom, verifyPlan, cacheEconomics, cacheHitRate, contextPressure, comparePrompts, compareToBaseline, computeSavings, countTokensAnthropic, DEFAULT_USAGE, detectFromSource, matchLocale, parsePlanDocument, waiverDay, waiverHistory, proposeInit, MIN_RATE_DAYS, parseConfig, coverageDrift, driversBetween, explainGateFailure, assignSources, fleetRollup, labelCoverage, measuredUsage, gateMargin, GATE_MARGIN_TIGHT, estimateTokens, evaluate, extractPrompts, findExamples, formatBaseline, formatSignedUsd, formatUsd, getMessages, getModel, hasMarker, LOCALES, MAX_BASELINE_BYTES, moneyIsComparable, mostSpecificMatch, nearestName, optimize, parseBaseline, PHRASE_LANGUAGES, plannedCalls, profilePrompt, profileToCsv, profileUsage, promptId, providerFromEnv, pruneExamples, refineWithLlm, rejectionText, reorderForCache, repriceProfile, reviewAgeDays, reviewExamples, RULES, sharedPrefixes, sharesOf, SOURCE_EXTENSIONS, suggestRewrites, toOtlpMetrics, toPromptfoo, TTL_1H_MS, UNLABELLED, withExactTokenCounts, } from '@trazum/core';
|
|
6
6
|
import { cacheDir, cacheStats, cachingProvider, clearCache } from './suggest-cache.js';
|
|
7
7
|
import { dayOf, formatGap, median, spanDays } from './time.js';
|
|
8
8
|
// Everything that reads the filesystem, on its own entry point so the web
|
|
@@ -11,6 +11,7 @@ import { CONFIG_FILENAME, DEFAULT_EXTENSIONS, budgetFor, BUNDLED_CATALOGUE, SAFE
|
|
|
11
11
|
import { contentAt, gitAvailable, namesByRevision, pathInRepository, repositoryRoot, revisionsFor, } from './git.js';
|
|
12
12
|
import { fetchProviderUsage, findCredential } from './connect.js';
|
|
13
13
|
import { STORE_DIR, appendRecords, readStore, rewriteStore } from './store-fs.js';
|
|
14
|
+
import { WAIVER_LOG, appendWaiverUse, readWaiverLog } from './waiver-log.js';
|
|
14
15
|
import { DEFAULT_PORT, buildServer, listen } from './serve.js';
|
|
15
16
|
import { WATCH_STATE_VERSION, checkWebhook, postWebhook, readWatchState, writeWatchState, } from './watch-run.js';
|
|
16
17
|
import { LOCALE_ENV_VARS, detectLocale, getCliMessages } from './i18n/index.js';
|
|
@@ -2518,7 +2519,7 @@ async function commandConnect(args, pricing, t) {
|
|
|
2518
2519
|
* same action planned twice — and no series, however long, becomes a
|
|
2519
2520
|
* forecast.
|
|
2520
2521
|
*/
|
|
2521
|
-
async function commandHistory(args, pricing, t) {
|
|
2522
|
+
async function commandHistory(args, config, pricing, t) {
|
|
2522
2523
|
/**
|
|
2523
2524
|
* `--store` builds the series from measured spend already on disk.
|
|
2524
2525
|
*
|
|
@@ -2617,7 +2618,22 @@ async function commandHistory(args, pricing, t) {
|
|
|
2617
2618
|
if (history.periods.length < 3) {
|
|
2618
2619
|
throw new Error(t.history.needsThree(String(history.periods.length)));
|
|
2619
2620
|
}
|
|
2620
|
-
|
|
2621
|
+
/**
|
|
2622
|
+
* The waiver record — closing the gap 1.40 named and could not fill.
|
|
2623
|
+
*
|
|
2624
|
+
* 1.40 wanted to say "this finding has been waived three times in a row" and
|
|
2625
|
+
* refused to, because the only material available was the config as it
|
|
2626
|
+
* stands, and a past reconstructed from a present is a guess wearing a
|
|
2627
|
+
* record's clothes. The material exists now: since 1.48 a waiver that
|
|
2628
|
+
* silences a gate writes down that it did, and this reads those lines back.
|
|
2629
|
+
*
|
|
2630
|
+
* Read from the working directory rather than from the reports directory:
|
|
2631
|
+
* the waiver record belongs to the repository whose gates fired, and the
|
|
2632
|
+
* stored reports may have come from anywhere.
|
|
2633
|
+
*/
|
|
2634
|
+
const waivers = await readWaiverLog('.');
|
|
2635
|
+
const waiverReport = waiverHistory(waivers.uses, config.waive ?? []);
|
|
2636
|
+
const stamped = { ...history, unrecognizedFiles: unrecognized, waivers: waiverReport };
|
|
2621
2637
|
const n = (value) => value.toLocaleString(t.numberLocale);
|
|
2622
2638
|
const day = (ms) => new Date(ms).toISOString().slice(0, 10);
|
|
2623
2639
|
const pct = (value) => `${(value * 100).toFixed(1)}%`;
|
|
@@ -2659,6 +2675,56 @@ async function commandHistory(args, pricing, t) {
|
|
|
2659
2675
|
for (const name of unrecognized) {
|
|
2660
2676
|
out.push(md ? `- ${t.history.unrecognized(name)}` : ` ${t.history.unrecognized(name)}`);
|
|
2661
2677
|
}
|
|
2678
|
+
/**
|
|
2679
|
+
* The waiver record, printed only once something has been recorded.
|
|
2680
|
+
*
|
|
2681
|
+
* Silent on a repository that has never waived anything, rather than a
|
|
2682
|
+
* heading over "0 uses" — an empty section teaches a reader to skip the
|
|
2683
|
+
* section, and this is the one they should not learn to skip.
|
|
2684
|
+
*/
|
|
2685
|
+
if (waivers.present) {
|
|
2686
|
+
out.push('');
|
|
2687
|
+
out.push(md ? `### ${t.history.waiverHeading()}` : t.history.waiverHeading());
|
|
2688
|
+
if (waiverReport.totalUses === 0) {
|
|
2689
|
+
out.push(md ? `- ${t.history.waiverNoneRecorded()}` : ` ${t.history.waiverNoneRecorded()}`);
|
|
2690
|
+
}
|
|
2691
|
+
else {
|
|
2692
|
+
const since = t.history.waiverSince(waiverReport.since ?? '', waiverReport.totalUses);
|
|
2693
|
+
out.push(md ? `- ${since}` : ` ${since}`);
|
|
2694
|
+
out.push(md ? `- _${t.history.waiverStartsHere()}_` : ` ${t.history.waiverStartsHere()}`);
|
|
2695
|
+
for (const habit of waiverReport.habits) {
|
|
2696
|
+
out.push('');
|
|
2697
|
+
const head = t.history.waiverHabit(habit.gate, habit.uses, habit.days, habit.firstDay, habit.lastDay);
|
|
2698
|
+
out.push(md ? `- **${head}**` : ` ${head}`);
|
|
2699
|
+
const rows = [t.history.waiverVerdict(habit.verdict)];
|
|
2700
|
+
// The reason as it stands *now* — never read backwards onto an
|
|
2701
|
+
// older use, which is the same mistake the record exists to avoid.
|
|
2702
|
+
const latest = habit.reasons[habit.reasons.length - 1];
|
|
2703
|
+
if (latest !== undefined)
|
|
2704
|
+
rows.push(t.history.waiverReasonNow(latest));
|
|
2705
|
+
if (habit.reasons.length > 1)
|
|
2706
|
+
rows.push(t.history.waiverReasonsChanged(habit.reasons.length));
|
|
2707
|
+
const firstExpiry = habit.expiries[0];
|
|
2708
|
+
const lastExpiry = habit.expiries[habit.expiries.length - 1];
|
|
2709
|
+
if (habit.expiries.length > 1 && firstExpiry !== undefined && lastExpiry !== undefined) {
|
|
2710
|
+
rows.push(t.history.waiverExpiriesMoved(firstExpiry, lastExpiry, habit.expiries.length - 1));
|
|
2711
|
+
}
|
|
2712
|
+
if (!habit.stillConfigured)
|
|
2713
|
+
rows.push(t.history.waiverNoLongerConfigured());
|
|
2714
|
+
for (const row of rows)
|
|
2715
|
+
out.push(md ? ` - ${row}` : ` ${row}`);
|
|
2716
|
+
}
|
|
2717
|
+
}
|
|
2718
|
+
if (waiverReport.neverUsed.length > 0) {
|
|
2719
|
+
out.push('');
|
|
2720
|
+
const dead = t.history.waiverNeverUsed(waiverReport.neverUsed.join(', '));
|
|
2721
|
+
out.push(md ? `- ${dead}` : ` ${dead}`);
|
|
2722
|
+
}
|
|
2723
|
+
if (waivers.unreadable.length > 0) {
|
|
2724
|
+
const bad = t.history.waiverUnreadable(waivers.unreadable.length, WAIVER_LOG);
|
|
2725
|
+
out.push(md ? `- ${bad}` : ` ${bad}`);
|
|
2726
|
+
}
|
|
2727
|
+
}
|
|
2662
2728
|
if (fromStore) {
|
|
2663
2729
|
out.push('');
|
|
2664
2730
|
const note = t.history.storeNoLabels();
|
|
@@ -2695,19 +2761,21 @@ async function commandVerify(args, pricing, t) {
|
|
|
2695
2761
|
const againstPath = stringFlag(args, 'against');
|
|
2696
2762
|
if (againstPath === undefined)
|
|
2697
2763
|
throw new Error(t.verify.needsAgainst());
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2764
|
+
/**
|
|
2765
|
+
* One validator, shared with the browser since 1.47.
|
|
2766
|
+
*
|
|
2767
|
+
* The check here used to be `schemaVersion === 1 && Array.isArray(actions)`
|
|
2768
|
+
* and nothing more, which accepts a file whose actions are arbitrary
|
|
2769
|
+
* objects — `verifyPlan` would then read `label` off `undefined`, match it
|
|
2770
|
+
* against no slice, and report `cannot-tell: workload-vanished` for every
|
|
2771
|
+
* one. A verification of a document that was never a plan, rendered exactly
|
|
2772
|
+
* like a real one.
|
|
2773
|
+
*/
|
|
2774
|
+
const parsed = parsePlanDocument(await readFile(planPath, 'utf8'));
|
|
2775
|
+
if (!parsed.ok) {
|
|
2776
|
+
throw new Error(t.verify.badPlan(planPath, t.verify.planRefusal(parsed.why)));
|
|
2710
2777
|
}
|
|
2778
|
+
const plan = parsed.plan;
|
|
2711
2779
|
const GZ = LOG_EXTENSIONS.map((ext) => `${ext}.gz`);
|
|
2712
2780
|
const READABLE = [...LOG_EXTENSIONS, ...GZ];
|
|
2713
2781
|
const target = await stat(againstPath).catch(() => null);
|
|
@@ -3330,7 +3398,16 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3330
3398
|
* way, because a waived failure that vanished from the output would be a
|
|
3331
3399
|
* finding deleted with extra steps.
|
|
3332
3400
|
*/
|
|
3333
|
-
|
|
3401
|
+
/**
|
|
3402
|
+
* Uses recorded this run, flushed after the gates have finished.
|
|
3403
|
+
*
|
|
3404
|
+
* Collected rather than written inline because `waived` is synchronous and
|
|
3405
|
+
* called from seven places inside the gate pass. Writing from each of them
|
|
3406
|
+
* would mean seven awaits threaded through the exit-code logic — the one
|
|
3407
|
+
* part of this command where a mistake turns a red build green.
|
|
3408
|
+
*/
|
|
3409
|
+
const waiverUses = [];
|
|
3410
|
+
const waived = (gate, measuredUsd = null, limitUsd = null) => {
|
|
3334
3411
|
const found = waiverFor(gate);
|
|
3335
3412
|
if (found === null)
|
|
3336
3413
|
return false;
|
|
@@ -3340,6 +3417,29 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3340
3417
|
}
|
|
3341
3418
|
const daysLeft = Math.max(0, Math.ceil((Date.parse(`${found.entry.until}T00:00:00Z`) + 86_400_000 - Date.now()) / 86_400_000));
|
|
3342
3419
|
console.error(c.yellow(t.profile.waiveActive(gate, found.entry.reason, found.entry.until, String(daysLeft))));
|
|
3420
|
+
/**
|
|
3421
|
+
* Recorded **when it silences something**, never when it is configured.
|
|
3422
|
+
*
|
|
3423
|
+
* A waiver nobody's build has ever hit is not a habit — it is dead config
|
|
3424
|
+
* — and the history reports the two apart. This is also the only honest
|
|
3425
|
+
* way to build the record 1.40 refused to invent: it starts today and
|
|
3426
|
+
* says so, rather than reconstructing a past from the present.
|
|
3427
|
+
*
|
|
3428
|
+
* The reason and the expiry are taken from the config **as it stands at
|
|
3429
|
+
* this moment**, because that is the decision that was actually in force.
|
|
3430
|
+
* Reading today's reason back onto last quarter's use is the same mistake
|
|
3431
|
+
* one layer down.
|
|
3432
|
+
*/
|
|
3433
|
+
waiverUses.push({
|
|
3434
|
+
schemaVersion: 1,
|
|
3435
|
+
day: waiverDay(new Date()),
|
|
3436
|
+
gate,
|
|
3437
|
+
reason: found.entry.reason,
|
|
3438
|
+
until: found.entry.until,
|
|
3439
|
+
commit: process.env.GITHUB_SHA ?? process.env.CI_COMMIT_SHA ?? null,
|
|
3440
|
+
measuredUsd,
|
|
3441
|
+
limitUsd,
|
|
3442
|
+
});
|
|
3343
3443
|
return true;
|
|
3344
3444
|
};
|
|
3345
3445
|
const applyGates = () => {
|
|
@@ -3389,7 +3489,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3389
3489
|
}
|
|
3390
3490
|
if (usd > limit) {
|
|
3391
3491
|
console.error(c.red(t.profile.labelBudgetFailed(label, formatUsd(usd), formatUsd(limit))));
|
|
3392
|
-
if (!waived(`byLabel:${label}
|
|
3492
|
+
if (!waived(`byLabel:${label}`, usd, limit))
|
|
3393
3493
|
process.exitCode = 1;
|
|
3394
3494
|
}
|
|
3395
3495
|
else {
|
|
@@ -3451,7 +3551,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3451
3551
|
* copy says so.
|
|
3452
3552
|
*/
|
|
3453
3553
|
explainFailure(report.total.totalUsd - maxUsd);
|
|
3454
|
-
if (!waived('maxUsd'))
|
|
3554
|
+
if (!waived('maxUsd', report.total.totalUsd, maxUsd))
|
|
3455
3555
|
process.exitCode = 1;
|
|
3456
3556
|
}
|
|
3457
3557
|
else {
|
|
@@ -3486,7 +3586,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3486
3586
|
}
|
|
3487
3587
|
else if (againstDelta > maxGrowth) {
|
|
3488
3588
|
console.error(c.red(t.profile.maxGrowthUsdFailed(formatSignedUsd(againstDelta), formatUsd(maxGrowth))));
|
|
3489
|
-
if (!waived('maxGrowthUsd'))
|
|
3589
|
+
if (!waived('maxGrowthUsd', againstDelta, maxGrowth))
|
|
3490
3590
|
process.exitCode = 1;
|
|
3491
3591
|
}
|
|
3492
3592
|
}
|
|
@@ -3503,12 +3603,12 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3503
3603
|
const gateCache = cacheEconomics(report.total);
|
|
3504
3604
|
if (gateCache.deltaUsd > maxLoss) {
|
|
3505
3605
|
console.error(c.red(t.profile.maxCacheLossFailed(formatUsd(gateCache.deltaUsd), formatUsd(maxLoss))));
|
|
3506
|
-
if (!waived('maxCacheLossUsd'))
|
|
3606
|
+
if (!waived('maxCacheLossUsd', gateCache.deltaUsd, maxLoss))
|
|
3507
3607
|
process.exitCode = 1;
|
|
3508
3608
|
}
|
|
3509
3609
|
else if (gateCache.worstCaseDeltaUsd > maxLoss) {
|
|
3510
3610
|
console.error(c.red(t.profile.maxCacheLossWorstCase(report.total.assumedWriteTtlCalls, formatUsd(gateCache.worstCaseDeltaUsd), formatUsd(maxLoss))));
|
|
3511
|
-
if (!waived('maxCacheLossUsd'))
|
|
3611
|
+
if (!waived('maxCacheLossUsd', gateCache.worstCaseDeltaUsd, maxLoss))
|
|
3512
3612
|
process.exitCode = 1;
|
|
3513
3613
|
}
|
|
3514
3614
|
else {
|
|
@@ -3554,7 +3654,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3554
3654
|
if (worst.usd > maxDay) {
|
|
3555
3655
|
console.error(c.red(`${t.profile.maxDayFailed(worst.day, formatUsd(worst.usd), formatUsd(maxDay))}${suspect}`));
|
|
3556
3656
|
explainFailure(worst.usd - maxDay, { namesLargest: true });
|
|
3557
|
-
if (!waived('maxDayUsd'))
|
|
3657
|
+
if (!waived('maxDayUsd', worst.usd, maxDay))
|
|
3558
3658
|
process.exitCode = 1;
|
|
3559
3659
|
}
|
|
3560
3660
|
else {
|
|
@@ -3596,7 +3696,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3596
3696
|
else if (report.sessionSpend.maxUsd > maxSession) {
|
|
3597
3697
|
console.error(c.red(t.profile.maxSessionFailed(formatUsd(report.sessionSpend.maxUsd), formatUsd(maxSession), n(report.sessionSpend.sessions))));
|
|
3598
3698
|
explainFailure(report.sessionSpend.maxUsd - maxSession);
|
|
3599
|
-
if (!waived('maxSessionUsd'))
|
|
3699
|
+
if (!waived('maxSessionUsd', report.sessionSpend.maxUsd, maxSession))
|
|
3600
3700
|
process.exitCode = 1;
|
|
3601
3701
|
}
|
|
3602
3702
|
else {
|
|
@@ -3629,6 +3729,26 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3629
3729
|
gateFailed = process.exitCode === 1;
|
|
3630
3730
|
}
|
|
3631
3731
|
};
|
|
3732
|
+
/**
|
|
3733
|
+
* Writes down every waiver that silenced something this run.
|
|
3734
|
+
*
|
|
3735
|
+
* **A failure here never fails the build.** The gate's job is the exit code;
|
|
3736
|
+
* a read-only checkout or a full disk must not turn a passing build red on
|
|
3737
|
+
* account of bookkeeping. The problem is reported and the gate's own verdict
|
|
3738
|
+
* stands — which is also why this runs after `recordGates` rather than
|
|
3739
|
+
* inside it: nothing about the exit code depends on the write.
|
|
3740
|
+
*/
|
|
3741
|
+
const recordWaiverUses = async () => {
|
|
3742
|
+
if (waiverUses.length === 0)
|
|
3743
|
+
return;
|
|
3744
|
+
for (const use of waiverUses) {
|
|
3745
|
+
const failed = await appendWaiverUse('.', use);
|
|
3746
|
+
if (failed !== null) {
|
|
3747
|
+
console.error(c.dim(t.profile.waiveNotRecorded(WAIVER_LOG, failed)));
|
|
3748
|
+
return;
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
};
|
|
3632
3752
|
/**
|
|
3633
3753
|
* The side files the caller asked for. Written on **both** output paths:
|
|
3634
3754
|
* under --json the human rendering returns early, and the first version of
|
|
@@ -3777,6 +3897,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3777
3897
|
...(whatIf !== null ? { whatIf } : {}),
|
|
3778
3898
|
}, null, 2));
|
|
3779
3899
|
recordGates();
|
|
3900
|
+
await recordWaiverUses();
|
|
3780
3901
|
await writeSideFiles();
|
|
3781
3902
|
return;
|
|
3782
3903
|
}
|
|
@@ -4784,6 +4905,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
4784
4905
|
}
|
|
4785
4906
|
reportProfileGaps(report, t, n, pricingStale);
|
|
4786
4907
|
recordGates();
|
|
4908
|
+
await recordWaiverUses();
|
|
4787
4909
|
await writeSideFiles();
|
|
4788
4910
|
}
|
|
4789
4911
|
/**
|
|
@@ -6080,7 +6202,7 @@ async function main() {
|
|
|
6080
6202
|
await commandVerify(args, pricing, t);
|
|
6081
6203
|
break;
|
|
6082
6204
|
case 'history':
|
|
6083
|
-
await commandHistory(args, pricing, t);
|
|
6205
|
+
await commandHistory(args, config, pricing, t);
|
|
6084
6206
|
break;
|
|
6085
6207
|
case 'connect':
|
|
6086
6208
|
await commandConnect(args, pricing, t);
|