@trazum/cli 1.50.2 → 1.50.4
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/gateway-server.d.ts +91 -0
- package/dist/gateway-server.d.ts.map +1 -0
- package/dist/gateway-server.js +290 -0
- package/dist/gateway-server.js.map +1 -0
- package/dist/i18n/en.d.ts.map +1 -1
- package/dist/i18n/en.js +53 -0
- package/dist/i18n/en.js.map +1 -1
- package/dist/i18n/es.d.ts.map +1 -1
- package/dist/i18n/es.js +55 -0
- package/dist/i18n/es.js.map +1 -1
- package/dist/i18n/types.d.ts +33 -0
- package/dist/i18n/types.d.ts.map +1 -1
- package/dist/index.js +188 -7
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/gateway-server.ts +350 -0
- package/src/i18n/en.ts +69 -0
- package/src/i18n/es.ts +71 -0
- package/src/i18n/types.ts +30 -0
- package/src/index.ts +256 -5
package/dist/index.js
CHANGED
|
@@ -4,7 +4,7 @@ import { open, readdir, readFile, stat, writeFile } from 'node:fs/promises';
|
|
|
4
4
|
import { dirname, join, resolve as resolvePath } from 'node:path';
|
|
5
5
|
import { fileURLToPath } from 'node:url';
|
|
6
6
|
import { gunzipSync } from 'node:zlib';
|
|
7
|
-
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, budgetPositions, conform, 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';
|
|
7
|
+
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, budgetPositions, conform, outcomeReport, FAILURE_POLICIES, 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';
|
|
8
8
|
import { cacheDir, cacheStats, cachingProvider, clearCache } from './suggest-cache.js';
|
|
9
9
|
import { dayOf, formatGap, median, spanDays } from './time.js';
|
|
10
10
|
// Everything that reads the filesystem, on its own entry point so the web
|
|
@@ -15,6 +15,7 @@ import { fetchProviderUsage, findCredential } from './connect.js';
|
|
|
15
15
|
import { STORE_DIR, appendRecords, readStore, rewriteStore } from './store-fs.js';
|
|
16
16
|
import { WAIVER_LOG, appendWaiverUse, readWaiverLog } from './waiver-log.js';
|
|
17
17
|
import { DEFAULT_PORT, buildServer, listen } from './serve.js';
|
|
18
|
+
import { DEFAULT_GATEWAY_PORT, UPSTREAMS, buildGateway, listenGateway, } from './gateway-server.js';
|
|
18
19
|
import { WATCH_STATE_VERSION, checkWebhook, postWebhook, readWatchState, writeWatchState, } from './watch-run.js';
|
|
19
20
|
import { LOCALE_ENV_VARS, detectLocale, getCliMessages } from './i18n/index.js';
|
|
20
21
|
import { MAX_SUMMARY_CHARS, fitWithin, renderBlameMarkdown, renderCheckMarkdown, renderDiffMarkdown, renderRankMarkdown, renderProfileMarkdown, } from './markdown.js';
|
|
@@ -33,6 +34,7 @@ const c = {
|
|
|
33
34
|
const VALUE_FLAGS = new Set([
|
|
34
35
|
'against',
|
|
35
36
|
'contract',
|
|
37
|
+
'on-cannot-tell',
|
|
36
38
|
'from-log',
|
|
37
39
|
'min-usd',
|
|
38
40
|
'payload',
|
|
@@ -316,6 +318,7 @@ const COMMAND_FLAGS = {
|
|
|
316
318
|
init: ['dry-run', 'yes', 'json', 'pricing', 'pricing-live'],
|
|
317
319
|
conform: ['contract', 'json'],
|
|
318
320
|
feedback: [],
|
|
321
|
+
gateway: ['on-cannot-tell', 'port', 'socket', 'pricing', 'pricing-live'],
|
|
319
322
|
where: [],
|
|
320
323
|
rules: [],
|
|
321
324
|
blame: ['limit', 'model', 'calls', 'output-tokens', 'batch', 'prompt', 'markdown-out'],
|
|
@@ -1575,6 +1578,93 @@ function commandFeedback(t) {
|
|
|
1575
1578
|
console.log(` ${url}`);
|
|
1576
1579
|
console.log();
|
|
1577
1580
|
}
|
|
1581
|
+
/**
|
|
1582
|
+
* `trazum gateway <provider>` — in the path, and refusing rather than advising.
|
|
1583
|
+
*
|
|
1584
|
+
* The last thing this product could not do. `serve` answers a question an
|
|
1585
|
+
* implementation may ignore; a connector reports the runaway after it ran.
|
|
1586
|
+
* Standing between the caller and the provider fixes both — usage is measured
|
|
1587
|
+
* from the provider's own response as it comes back, and a refusal is a
|
|
1588
|
+
* refusal.
|
|
1589
|
+
*
|
|
1590
|
+
* **The failure policy is required.** `--on-cannot-tell fail-open` keeps the
|
|
1591
|
+
* product working and lets the bill run; `fail-closed` stops the bill and takes
|
|
1592
|
+
* the product down with it. Both are defensible and there is deliberately no
|
|
1593
|
+
* default: a proxy that picks silently has made the most consequential decision
|
|
1594
|
+
* in somebody's architecture on their behalf, at install time, without saying
|
|
1595
|
+
* so.
|
|
1596
|
+
*
|
|
1597
|
+
* **Substitution is off unless it is written down.** `spend.substitute` in the
|
|
1598
|
+
* config, with the operator's own reason, and every substituted call is marked
|
|
1599
|
+
* so no later report treats it as the call the caller made.
|
|
1600
|
+
*/
|
|
1601
|
+
async function commandGateway(args, config, configDir, pricing, t) {
|
|
1602
|
+
const provider = args.positional[0];
|
|
1603
|
+
if (provider === undefined || UPSTREAMS[provider] === undefined) {
|
|
1604
|
+
throw new Error(t.gateway.badProvider(provider ?? '', Object.keys(UPSTREAMS).join(', ')));
|
|
1605
|
+
}
|
|
1606
|
+
/**
|
|
1607
|
+
* No default, and the error says why rather than just what.
|
|
1608
|
+
*
|
|
1609
|
+
* The one flag in this product that refuses to guess on the reader's behalf,
|
|
1610
|
+
* because the two answers differ in which failure they accept and nobody but
|
|
1611
|
+
* the operator knows which their product can survive.
|
|
1612
|
+
*/
|
|
1613
|
+
const policyFlag = stringFlag(args, 'on-cannot-tell');
|
|
1614
|
+
if (policyFlag === undefined || !FAILURE_POLICIES.includes(policyFlag)) {
|
|
1615
|
+
throw new Error(t.gateway.needsPolicy(FAILURE_POLICIES.join(', ')));
|
|
1616
|
+
}
|
|
1617
|
+
const { resolved } = await readStore(configDir);
|
|
1618
|
+
const budget = budgetPositions(resolved.records, config.spend, { catalogue: pricing });
|
|
1619
|
+
const position = budget.positions[0] ?? null;
|
|
1620
|
+
/**
|
|
1621
|
+
* Read once at start, like `serve`'s.
|
|
1622
|
+
*
|
|
1623
|
+
* A file read in the request path would put Trazum's own latency between a
|
|
1624
|
+
* caller and their provider on every call, which is a cost this product
|
|
1625
|
+
* would otherwise be reporting on somebody else. The staleness is real, so a
|
|
1626
|
+
* refusal carries `asOfMs` and says what it rested on.
|
|
1627
|
+
*/
|
|
1628
|
+
const standing = position === null || position.coverage === 'none'
|
|
1629
|
+
? null
|
|
1630
|
+
: {
|
|
1631
|
+
limitUsd: position.limitUsd,
|
|
1632
|
+
consumedUsd: position.consumedUsd,
|
|
1633
|
+
provenance: 'measured',
|
|
1634
|
+
asOfMs: Date.now(),
|
|
1635
|
+
};
|
|
1636
|
+
const measured = { calls: 0, usd: 0 };
|
|
1637
|
+
const server = buildGateway({
|
|
1638
|
+
provider,
|
|
1639
|
+
catalogue: pricing,
|
|
1640
|
+
policy: {
|
|
1641
|
+
onCannotTell: policyFlag,
|
|
1642
|
+
...(config.spend?.substitute === undefined ? {} : { substitute: config.spend.substitute }),
|
|
1643
|
+
},
|
|
1644
|
+
standing: () => standing,
|
|
1645
|
+
record: (call) => {
|
|
1646
|
+
measured.calls += 1;
|
|
1647
|
+
console.error(c.dim(t.gateway.measured(call.model, call.label, call.inputTokens, call.outputTokens, call.substituted)));
|
|
1648
|
+
},
|
|
1649
|
+
note: (line) => {
|
|
1650
|
+
console.error(c.yellow(` ${line}`));
|
|
1651
|
+
},
|
|
1652
|
+
});
|
|
1653
|
+
const socket = stringFlag(args, 'socket');
|
|
1654
|
+
const portRaw = stringFlag(args, 'port');
|
|
1655
|
+
const port = portRaw === undefined ? DEFAULT_GATEWAY_PORT : Number(portRaw);
|
|
1656
|
+
if (socket === undefined && (!Number.isInteger(port) || port < 0 || port > 65_535)) {
|
|
1657
|
+
throw new Error(t.serve.badPort(String(portRaw)));
|
|
1658
|
+
}
|
|
1659
|
+
const where = await listenGateway(server, socket !== undefined ? { socket } : { port });
|
|
1660
|
+
console.log(c.bold(t.gateway.listening(where, provider)));
|
|
1661
|
+
console.log(` ${c.dim(wrap(t.gateway.pointYourSdk(where), 74, ' '))}`);
|
|
1662
|
+
console.log(` ${c.dim(wrap(t.gateway.credential(), 74, ' '))}`);
|
|
1663
|
+
console.log(` ${c.dim(wrap(t.gateway.neverSubstitutes(), 74, ' '))}`);
|
|
1664
|
+
console.log(` ${c.dim(wrap(standing === null ? t.gateway.noStanding() : t.gateway.standing(formatUsd(standing.consumedUsd), formatUsd(standing.limitUsd)), 74, ' '))}`);
|
|
1665
|
+
console.log(` ${c.dim(wrap(t.gateway.policy(policyFlag), 74, ' '))}`);
|
|
1666
|
+
console.log();
|
|
1667
|
+
}
|
|
1578
1668
|
function commandModels(t, pricing) {
|
|
1579
1669
|
const n = (value) => value.toLocaleString(t.numberLocale);
|
|
1580
1670
|
const col = t.models.columns;
|
|
@@ -2761,7 +2851,7 @@ async function commandConnect(args, pricing, t) {
|
|
|
2761
2851
|
* same action planned twice — and no series, however long, becomes a
|
|
2762
2852
|
* forecast.
|
|
2763
2853
|
*/
|
|
2764
|
-
async function commandHistory(args, config, pricing, t) {
|
|
2854
|
+
async function commandHistory(args, config, configDir, pricing, t) {
|
|
2765
2855
|
/**
|
|
2766
2856
|
* `--store` builds the series from measured spend already on disk.
|
|
2767
2857
|
*
|
|
@@ -2873,7 +2963,7 @@ async function commandHistory(args, config, pricing, t) {
|
|
|
2873
2963
|
* the waiver record belongs to the repository whose gates fired, and the
|
|
2874
2964
|
* stored reports may have come from anywhere.
|
|
2875
2965
|
*/
|
|
2876
|
-
const waivers = await readWaiverLog(
|
|
2966
|
+
const waivers = await readWaiverLog(configDir);
|
|
2877
2967
|
const waiverReport = waiverHistory(waivers.uses, config.waive ?? []);
|
|
2878
2968
|
const stamped = { ...history, unrecognizedFiles: unrecognized, waivers: waiverReport };
|
|
2879
2969
|
const n = (value) => value.toLocaleString(t.numberLocale);
|
|
@@ -3225,7 +3315,7 @@ async function commandPlan(args, pricing, t) {
|
|
|
3225
3315
|
if (outPath !== undefined)
|
|
3226
3316
|
console.log(c.dim(wrap(t.plan.wrote(outPath), 74, '')));
|
|
3227
3317
|
}
|
|
3228
|
-
async function commandProfile(args, config, pricing, t) {
|
|
3318
|
+
async function commandProfile(args, config, configDir, pricing, t) {
|
|
3229
3319
|
const path = args.positional[0];
|
|
3230
3320
|
if (path === undefined) {
|
|
3231
3321
|
console.log();
|
|
@@ -3497,6 +3587,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3497
3587
|
can(cov.label > 0, t.profile.dryRunLabels(share(cov.label)));
|
|
3498
3588
|
can(cov.ts > 0, t.profile.dryRunClock(share(cov.ts)));
|
|
3499
3589
|
can(cov.session > 0, t.profile.dryRunSessions(share(cov.session)));
|
|
3590
|
+
can(cov.outcome > 0, t.profile.dryRunOutcomes(share(cov.outcome)));
|
|
3500
3591
|
can(cov.stopReason > 0, t.profile.dryRunStopReason(share(cov.stopReason)));
|
|
3501
3592
|
// "No cache traffic" is not a missing field: the split can only exist on
|
|
3502
3593
|
// records that wrote, and a log that never wrote has nothing to record.
|
|
@@ -3984,7 +4075,7 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
3984
4075
|
if (waiverUses.length === 0)
|
|
3985
4076
|
return;
|
|
3986
4077
|
for (const use of waiverUses) {
|
|
3987
|
-
const failed = await appendWaiverUse(
|
|
4078
|
+
const failed = await appendWaiverUse(configDir, use);
|
|
3988
4079
|
if (failed !== null) {
|
|
3989
4080
|
console.error(c.dim(t.profile.waiveNotRecorded(WAIVER_LOG, failed)));
|
|
3990
4081
|
return;
|
|
@@ -5119,6 +5210,69 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
5119
5210
|
* section at all, because a paragraph of things that are fine is the
|
|
5120
5211
|
* paragraph readers learn to skip.
|
|
5121
5212
|
*/
|
|
5213
|
+
/**
|
|
5214
|
+
* Outcomes — the counterpart, where somebody recorded one.
|
|
5215
|
+
*
|
|
5216
|
+
* Printed above the coverage section rather than below it, because when this
|
|
5217
|
+
* section is present it is the most valuable thing on the page: every other
|
|
5218
|
+
* figure in this report is a cost, and this is the only one that says what
|
|
5219
|
+
* the money bought.
|
|
5220
|
+
*
|
|
5221
|
+
* Silent when nothing recorded an outcome. The coverage section below
|
|
5222
|
+
* already names the missing field and what it would unlock, and printing an
|
|
5223
|
+
* empty Outcomes heading above it would be the same sentence twice.
|
|
5224
|
+
*/
|
|
5225
|
+
{
|
|
5226
|
+
const outcomes = outcomeReport(report.outcomeTally, config.outcomes ?? null);
|
|
5227
|
+
if (outcomes.coverage.recorded > 0) {
|
|
5228
|
+
console.log();
|
|
5229
|
+
console.log(c.bold(t.profile.outcomeHeading()));
|
|
5230
|
+
const col = t.profile.outcomeColumns;
|
|
5231
|
+
const rows = [...outcomes.slices, ...outcomes.undeclared].map((slice) => ({
|
|
5232
|
+
value: slice.value,
|
|
5233
|
+
verdict: slice.verdict === 'success'
|
|
5234
|
+
? t.profile.verdictSuccess()
|
|
5235
|
+
: slice.verdict === 'undeclared'
|
|
5236
|
+
? t.profile.verdictUndeclared()
|
|
5237
|
+
: t.profile.verdictOther(),
|
|
5238
|
+
calls: n(slice.calls),
|
|
5239
|
+
spend: formatUsd(slice.usd),
|
|
5240
|
+
}));
|
|
5241
|
+
const w = {
|
|
5242
|
+
value: Math.max(...rows.map((r) => r.value.length), col.outcome.length),
|
|
5243
|
+
verdict: Math.max(...rows.map((r) => r.verdict.length), 0),
|
|
5244
|
+
calls: Math.max(...rows.map((r) => r.calls.length), col.calls.length),
|
|
5245
|
+
spend: Math.max(...rows.map((r) => r.spend.length), col.spend.length),
|
|
5246
|
+
};
|
|
5247
|
+
console.log(c.dim(` ${col.outcome.padEnd(w.value)} ${''.padEnd(w.verdict)} ` +
|
|
5248
|
+
`${col.calls.padStart(w.calls)} ${col.spend.padStart(w.spend)}`));
|
|
5249
|
+
for (const row of rows) {
|
|
5250
|
+
const tint = row.verdict === t.profile.verdictUndeclared()
|
|
5251
|
+
? c.yellow
|
|
5252
|
+
: row.verdict === t.profile.verdictSuccess()
|
|
5253
|
+
? c.green
|
|
5254
|
+
: c.dim;
|
|
5255
|
+
console.log(` ${row.value.padEnd(w.value)} ${tint(row.verdict.padEnd(w.verdict))} ` +
|
|
5256
|
+
`${row.calls.padStart(w.calls)} ${row.spend.padStart(w.spend)}`);
|
|
5257
|
+
}
|
|
5258
|
+
console.log();
|
|
5259
|
+
if (outcomes.successShareOfRecordedUsd !== null) {
|
|
5260
|
+
const declaredUsd = outcomes.slices.reduce((sum, slice) => sum + slice.usd, 0);
|
|
5261
|
+
console.log(` ${wrap(t.profile.outcomeRate(pct(outcomes.successShareOfRecordedUsd), formatUsd(declaredUsd)), 74, ' ')}`);
|
|
5262
|
+
}
|
|
5263
|
+
else if (outcomes.noRate !== null) {
|
|
5264
|
+
console.log(` ${c.dim(wrap(t.profile.outcomeNoRate(outcomes.noRate), 74, ' '))}`);
|
|
5265
|
+
}
|
|
5266
|
+
// What the rate does not cover, every time it is printed. A rate over a
|
|
5267
|
+
// twelfth of the bill is a rate about a twelfth of the bill.
|
|
5268
|
+
if (outcomes.coverage.unrecordedUsd > 0 && report.total.totalUsd > 0) {
|
|
5269
|
+
console.log(` ${c.yellow('!')} ${wrap(t.profile.outcomeUnrecorded(pct(outcomes.coverage.unrecordedUsd / report.total.totalUsd), formatUsd(outcomes.coverage.unrecordedUsd)), 74, ' ')}`);
|
|
5270
|
+
}
|
|
5271
|
+
if (outcomes.undeclared.length > 0) {
|
|
5272
|
+
console.log(` ${c.yellow('!')} ${wrap(t.profile.outcomeUndeclared(outcomes.undeclared.map((s) => s.value).join(', ')), 74, ' ')}`);
|
|
5273
|
+
}
|
|
5274
|
+
}
|
|
5275
|
+
}
|
|
5122
5276
|
const coverage = report.fieldCoverage;
|
|
5123
5277
|
if (coverage.parsed > 0) {
|
|
5124
5278
|
const missing = [];
|
|
@@ -5129,6 +5283,14 @@ async function commandProfile(args, config, pricing, t) {
|
|
|
5129
5283
|
if (coverage.session < coverage.parsed) {
|
|
5130
5284
|
missing.push(t.profile.needsSession(partial(coverage.session)));
|
|
5131
5285
|
}
|
|
5286
|
+
/**
|
|
5287
|
+
* Listed first among the missing when it is missing entirely, because it
|
|
5288
|
+
* is the one field that changes what every other figure here *means*. The
|
|
5289
|
+
* rest sharpen a cost; this one gives it a counterpart.
|
|
5290
|
+
*/
|
|
5291
|
+
if (coverage.outcome < coverage.parsed) {
|
|
5292
|
+
missing.push(t.profile.needsOutcome(partial(coverage.outcome)));
|
|
5293
|
+
}
|
|
5132
5294
|
if (coverage.ts < coverage.parsed) {
|
|
5133
5295
|
missing.push(t.profile.needsTs(partial(coverage.ts)));
|
|
5134
5296
|
}
|
|
@@ -6431,6 +6593,22 @@ async function main() {
|
|
|
6431
6593
|
};
|
|
6432
6594
|
}
|
|
6433
6595
|
const { config } = loaded;
|
|
6596
|
+
/**
|
|
6597
|
+
* Where the waiver record lives: **beside the config that declared it**.
|
|
6598
|
+
*
|
|
6599
|
+
* It used to be the process's working directory, which is a different place
|
|
6600
|
+
* whenever somebody runs `trazum profile ../logs/x.jsonl --config ../repo/
|
|
6601
|
+
* trazum.config.json` — and that is not hypothetical. This repository's own
|
|
6602
|
+
* test suite did exactly that from `packages/cli`, so sixty records of a
|
|
6603
|
+
* fixture's decisions accumulated in a package directory and one of them was
|
|
6604
|
+
* committed to `main`, where it sat for two releases.
|
|
6605
|
+
*
|
|
6606
|
+
* A waiver is a decision a *repository* made. The record of using it belongs
|
|
6607
|
+
* with the file that made it, not with wherever the terminal happened to be.
|
|
6608
|
+
* No config means no waivers, so there is nothing to write and `.` is never
|
|
6609
|
+
* reached.
|
|
6610
|
+
*/
|
|
6611
|
+
const configDir = loaded.path === null ? '.' : dirname(loaded.path);
|
|
6434
6612
|
const pricing = await pricingFor(args, loaded, t);
|
|
6435
6613
|
// The config only gets to choose the locale when nothing more explicit did.
|
|
6436
6614
|
if (config.locale && !stringFlag(args, 'locale')) {
|
|
@@ -6448,7 +6626,7 @@ async function main() {
|
|
|
6448
6626
|
await commandBaseline(args, config, pricing, t, locale);
|
|
6449
6627
|
break;
|
|
6450
6628
|
case 'profile':
|
|
6451
|
-
await commandProfile(args, config, pricing, t);
|
|
6629
|
+
await commandProfile(args, config, configDir, pricing, t);
|
|
6452
6630
|
break;
|
|
6453
6631
|
case 'plan':
|
|
6454
6632
|
await commandPlan(args, pricing, t);
|
|
@@ -6457,7 +6635,7 @@ async function main() {
|
|
|
6457
6635
|
await commandVerify(args, pricing, t);
|
|
6458
6636
|
break;
|
|
6459
6637
|
case 'history':
|
|
6460
|
-
await commandHistory(args, config, pricing, t);
|
|
6638
|
+
await commandHistory(args, config, configDir, pricing, t);
|
|
6461
6639
|
break;
|
|
6462
6640
|
case 'connect':
|
|
6463
6641
|
await commandConnect(args, pricing, t);
|
|
@@ -6486,6 +6664,9 @@ async function main() {
|
|
|
6486
6664
|
case 'models':
|
|
6487
6665
|
commandModels(t, pricing);
|
|
6488
6666
|
break;
|
|
6667
|
+
case 'gateway':
|
|
6668
|
+
await commandGateway(args, config, configDir, pricing, t);
|
|
6669
|
+
break;
|
|
6489
6670
|
case 'feedback':
|
|
6490
6671
|
commandFeedback(t);
|
|
6491
6672
|
break;
|