@mafdet/cli 0.4.9 → 0.4.10
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/CHANGELOG.md +33 -0
- package/README.md +3 -3
- package/README.zh-CN.md +1 -1
- package/dist/agent/loop.d.ts +13 -0
- package/dist/agent/loop.d.ts.map +1 -1
- package/dist/agent/loop.js +40 -13
- package/dist/commands/agent.d.ts.map +1 -1
- package/dist/commands/agent.js +3 -2
- package/dist/commands/embed.d.ts.map +1 -1
- package/dist/commands/embed.js +2 -2
- package/dist/commands/runtime.d.ts +16 -1
- package/dist/commands/runtime.d.ts.map +1 -1
- package/dist/commands/runtime.js +25 -6
- package/dist/commands/speech.d.ts.map +1 -1
- package/dist/commands/speech.js +2 -2
- package/dist/sessions/usage.d.ts.map +1 -1
- package/dist/sessions/usage.js +10 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,36 @@ The version is the contract for the JSON output shapes and the exit codes.
|
|
|
6
6
|
Being 0.x, semver still permits a break in a minor bump; the intent is not to
|
|
7
7
|
use that latitude, and the promise becomes binding at 1.0.0.
|
|
8
8
|
|
|
9
|
+
## 0.4.10 - 2026-08-12
|
|
10
|
+
|
|
11
|
+
A sixth audit round, and the finding that matters most is about how the last
|
|
12
|
+
one was tested.
|
|
13
|
+
|
|
14
|
+
**Every human-readable error now goes through one function.** 0.4.9 said this
|
|
15
|
+
and it was not true: `embed` and `speech` handled a surface mismatch
|
|
16
|
+
themselves, `mafdet agent` printed the upstream's message directly, and the
|
|
17
|
+
request id - which comes from a response header - was concatenated outside the
|
|
18
|
+
sanitiser inside the very function meant to be the boundary. Four paths, all
|
|
19
|
+
carrying remote text to a terminal.
|
|
20
|
+
|
|
21
|
+
The test that was supposed to cover this called the sanitiser directly, so it
|
|
22
|
+
passed while every caller bypassed it. That is the same mistake as the one in
|
|
23
|
+
0.4.7, one release later. The new tests go in at `embedCommand`,
|
|
24
|
+
`speechCommand` and `agentCommand` - the commands a user actually runs - and
|
|
25
|
+
each was checked to fail when its fix is removed.
|
|
26
|
+
|
|
27
|
+
**A cost ceiling refuses an unusable price before sending anything.** The
|
|
28
|
+
pre-flight check asked only whether the price fields were present, so `abc`,
|
|
29
|
+
`-1`, `1.5` and `" 2"` passed it and the run spent one request before the
|
|
30
|
+
post-response check refused the result. Both checks now share one definition,
|
|
31
|
+
which also fixes the opposite error: a price of `"0"` is a price, and a truthy
|
|
32
|
+
test was rejecting free models.
|
|
33
|
+
|
|
34
|
+
**An invalid token count no longer reaches the totals.** It had stopped
|
|
35
|
+
affecting cost, but a negative or fractional figure was still added to the
|
|
36
|
+
token summary and fed into the context estimate - producing negative totals
|
|
37
|
+
and steering a decision about what to send next.
|
|
38
|
+
|
|
9
39
|
## 0.4.9 - 2026-08-12
|
|
10
40
|
|
|
11
41
|
A fifth audit round: two billing and terminal-safety fixes, and two smaller
|
|
@@ -21,6 +51,9 @@ present and valid; anything else is reported as unpriced, stops a run that
|
|
|
21
51
|
asked for a ceiling, and keeps the answer that was generated.
|
|
22
52
|
|
|
23
53
|
**Errors and diagnostics can no longer carry terminal control sequences.**
|
|
54
|
+
⚠️ Not true as written: `doctor` and the shared reporter were fixed, but
|
|
55
|
+
`embed`, `speech`, the agent's summary and the request id still bypassed it.
|
|
56
|
+
Fixed in 0.4.10.
|
|
24
57
|
`mafdet doctor` interpolated a model's `apiSurface` straight into its table,
|
|
25
58
|
and a surface-mismatch error did the same into stderr. Rather than cleaning
|
|
26
59
|
those two strings, the cleaning now happens at the two boundaries every
|
package/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
The official Mafdet AI command line: model calls, account queries, and a
|
|
4
4
|
permissioned local agent.
|
|
5
5
|
|
|
6
|
-
> **0.4.
|
|
6
|
+
> **0.4.10.** 中文版见 [README.zh-CN.md](./README.zh-CN.md). The CLI never
|
|
7
7
|
> advertises a command it cannot serve, so `mafdet help` always lists exactly
|
|
8
8
|
> what works.
|
|
9
9
|
>
|
|
@@ -23,8 +23,8 @@ Or build it from this repository:
|
|
|
23
23
|
|
|
24
24
|
```bash
|
|
25
25
|
pnpm --filter @mafdet/cli build
|
|
26
|
-
cd packages/cli && npm pack # -> mafdet-cli-0.4.
|
|
27
|
-
npm install -g ./mafdet-cli-0.4.
|
|
26
|
+
cd packages/cli && npm pack # -> mafdet-cli-0.4.10.tgz
|
|
27
|
+
npm install -g ./mafdet-cli-0.4.10.tgz
|
|
28
28
|
```
|
|
29
29
|
|
|
30
30
|
## The interactive session
|
package/README.zh-CN.md
CHANGED
package/dist/agent/loop.d.ts
CHANGED
|
@@ -167,5 +167,18 @@ interface ToolCall {
|
|
|
167
167
|
export declare function runAgent(options: AgentOptions): Promise<AgentReport>;
|
|
168
168
|
/** Retry-After when the server gave one; otherwise exponential with jitter. */
|
|
169
169
|
export declare function backoffMs(retryAfterSeconds: number | undefined, attempt: number, random?: () => number): number;
|
|
170
|
+
/**
|
|
171
|
+
* W-1 · Can this model be priced at all, before anything is sent?
|
|
172
|
+
*
|
|
173
|
+
* Exported and shared with the pre-flight check, because the two used to
|
|
174
|
+
* disagree: the check asked only whether the fields were truthy, so `abc`,
|
|
175
|
+
* `-1`, `1.5` and `" 2"` all passed it and the run spent one request before
|
|
176
|
+
* `canPrice` refused the result. A ceiling that cannot cover the first request
|
|
177
|
+
* is not the ceiling the user asked for.
|
|
178
|
+
*
|
|
179
|
+
* Note `"0"` is a valid price and truthy checks got that wrong in the other
|
|
180
|
+
* direction - a free model would have been refused.
|
|
181
|
+
*/
|
|
182
|
+
export declare function hasValidPrices(model: CatalogModel | undefined): boolean;
|
|
170
183
|
export {};
|
|
171
184
|
//# sourceMappingURL=loop.d.ts.map
|
package/dist/agent/loop.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"loop.d.ts","sourceRoot":"","sources":["../../src/agent/loop.ts"],"names":[],"mappings":"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"}
|
package/dist/agent/loop.js
CHANGED
|
@@ -54,11 +54,10 @@ export async function runAgent(options) {
|
|
|
54
54
|
// discover it meant a run with an explicit ceiling still made one billable
|
|
55
55
|
// request that could never be counted against it.
|
|
56
56
|
if (limits.maxCostMicroUsd !== undefined &&
|
|
57
|
-
(
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
`Re-run without the limit to continue anyway.`);
|
|
57
|
+
!hasValidPrices(options.pricing)) {
|
|
58
|
+
return stop(report, "cost_unknown", `--max-cost-usd cannot be enforced: the catalogue publishes no usable ` +
|
|
59
|
+
`price for ${options.model}, so nothing can be counted towards the ` +
|
|
60
|
+
`ceiling. Re-run without the limit to continue anyway.`);
|
|
62
61
|
}
|
|
63
62
|
for (let turn = 1; turn <= limits.maxTurns; turn += 1) {
|
|
64
63
|
if (options.signal?.aborted)
|
|
@@ -125,13 +124,24 @@ export async function runAgent(options) {
|
|
|
125
124
|
}
|
|
126
125
|
return stop(report, "error", error instanceof Error ? error.message : String(error));
|
|
127
126
|
}
|
|
127
|
+
// W-3 · Only counts that survive validation reach the totals or the
|
|
128
|
+
// context state. A negative or fractional figure used to be added to the
|
|
129
|
+
// report and fed into the compaction ratio - it no longer priced anything,
|
|
130
|
+
// but it still produced negative token totals and steered a decision about
|
|
131
|
+
// what to send next.
|
|
128
132
|
const usage = response.usage;
|
|
129
|
-
|
|
130
|
-
|
|
133
|
+
const promptTokens = isTokenCount(usage?.prompt_tokens)
|
|
134
|
+
? usage.prompt_tokens
|
|
135
|
+
: undefined;
|
|
136
|
+
const completionTokens = isTokenCount(usage?.completion_tokens)
|
|
137
|
+
? usage.completion_tokens
|
|
138
|
+
: undefined;
|
|
139
|
+
if (promptTokens !== undefined) {
|
|
140
|
+
lastPromptTokens = promptTokens;
|
|
131
141
|
lastRequestSize = sentSize;
|
|
132
142
|
}
|
|
133
|
-
report.promptTokens +=
|
|
134
|
-
report.completionTokens +=
|
|
143
|
+
report.promptTokens += promptTokens ?? 0;
|
|
144
|
+
report.completionTokens += completionTokens ?? 0;
|
|
135
145
|
// Cost comes from returned usage, never from the reservation: CLI-000B
|
|
136
146
|
// showed the reserve cannot see the tool schema and under-counts badly.
|
|
137
147
|
const turnCost = priceTurn(options.pricing, usage);
|
|
@@ -142,8 +152,10 @@ export async function runAgent(options) {
|
|
|
142
152
|
...(response.requestId === undefined
|
|
143
153
|
? {}
|
|
144
154
|
: { requestId: response.requestId }),
|
|
145
|
-
|
|
146
|
-
|
|
155
|
+
// W-3 · The validated values, so nothing downstream - the recorder, the
|
|
156
|
+
// session store, a JSON consumer - has to re-derive what was usable.
|
|
157
|
+
promptTokens: promptTokens ?? 0,
|
|
158
|
+
completionTokens: completionTokens ?? 0,
|
|
147
159
|
costMicroUsd: turnCost,
|
|
148
160
|
priced: canPrice(options.pricing, usage),
|
|
149
161
|
});
|
|
@@ -337,6 +349,22 @@ function isTokenCount(value) {
|
|
|
337
349
|
function isPrice(value) {
|
|
338
350
|
return typeof value === "string" && /^\d+$/.test(value);
|
|
339
351
|
}
|
|
352
|
+
/**
|
|
353
|
+
* W-1 · Can this model be priced at all, before anything is sent?
|
|
354
|
+
*
|
|
355
|
+
* Exported and shared with the pre-flight check, because the two used to
|
|
356
|
+
* disagree: the check asked only whether the fields were truthy, so `abc`,
|
|
357
|
+
* `-1`, `1.5` and `" 2"` all passed it and the run spent one request before
|
|
358
|
+
* `canPrice` refused the result. A ceiling that cannot cover the first request
|
|
359
|
+
* is not the ceiling the user asked for.
|
|
360
|
+
*
|
|
361
|
+
* Note `"0"` is a valid price and truthy checks got that wrong in the other
|
|
362
|
+
* direction - a free model would have been refused.
|
|
363
|
+
*/
|
|
364
|
+
export function hasValidPrices(model) {
|
|
365
|
+
return (isPrice(model?.inputPricePer1mMicroUsd) &&
|
|
366
|
+
isPrice(model?.outputPricePer1mMicroUsd));
|
|
367
|
+
}
|
|
340
368
|
function canPrice(model, usage) {
|
|
341
369
|
if (usage === undefined)
|
|
342
370
|
return false;
|
|
@@ -344,8 +372,7 @@ function canPrice(model, usage) {
|
|
|
344
372
|
return false;
|
|
345
373
|
if (!isTokenCount(usage.completion_tokens))
|
|
346
374
|
return false;
|
|
347
|
-
return (
|
|
348
|
-
isPrice(model?.outputPricePer1mMicroUsd));
|
|
375
|
+
return hasValidPrices(model);
|
|
349
376
|
}
|
|
350
377
|
function priceTurn(model, usage) {
|
|
351
378
|
// V-1 · One gate, shared with the caller's reporting, so a turn can never be
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAQA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAiBvE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD,OAAO,
|
|
1
|
+
{"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/commands/agent.ts"],"names":[],"mappings":"AAQA,OAAO,EAAe,KAAK,YAAY,EAAE,MAAM,uBAAuB,CAAC;AAiBvE,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAmBtB,eAAO,MAAM,gBAAgB,0XAK+C,CAAC;AAE7E,eAAO,MAAM,YAAY,mgBAOmB,CAAC;AAE7C,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,qDAAqD;IACrD,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,uBAAuB,EAAE,QAAQ,CAAC;IACpD;;;;;;OAMG;IACH,QAAQ,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;CAC9C;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,OAAO,GACV,OAAO,CAAC,QAAQ,CAAC,CAuInB;AAoLD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,YAAY,EAAE,kBAAkB,EAAE,OAAO,0JAI3E"}
|
package/dist/commands/agent.js
CHANGED
|
@@ -17,7 +17,7 @@ import { Workspace, WorkspaceError } from "../filesystem/workspace.js";
|
|
|
17
17
|
import { ExitCode } from "../output/exit-codes.js";
|
|
18
18
|
import { renderJson, renderRecord } from "../output/format.js";
|
|
19
19
|
import { formatUsdWithUnpriced } from "../output/money.js";
|
|
20
|
-
import { buildRuntime, reportError, requireApiKey, } from "./runtime.js";
|
|
20
|
+
import { buildRuntime, reportError, writeHumanError, requireApiKey, } from "./runtime.js";
|
|
21
21
|
const USAGE = `Usage:
|
|
22
22
|
mafdet agent "<goal>" [--model <id>] [--allow-write] [--read-only]
|
|
23
23
|
[--allow-command "<prefix>"]... [--max-turns <n>]
|
|
@@ -383,8 +383,9 @@ function finish(report, json, io) {
|
|
|
383
383
|
`~${formatUsdWithUnpriced(report.costMicroUsd, report.unpricedRequests)}`,
|
|
384
384
|
],
|
|
385
385
|
]));
|
|
386
|
+
// W-2 · `report.error` is the upstream's message, verbatim.
|
|
386
387
|
if (report.error)
|
|
387
|
-
io
|
|
388
|
+
writeHumanError(io, `error: ${report.error}\n`);
|
|
388
389
|
}
|
|
389
390
|
switch (report.stopReason) {
|
|
390
391
|
case "completed":
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../../src/commands/embed.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,
|
|
1
|
+
{"version":3,"file":"embed.d.ts","sourceRoot":"","sources":["../../src/commands/embed.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAQtB,MAAM,WAAW,OAAQ,SAAQ,SAAS;IACxC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,wBAAsB,YAAY,CAChC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,OAAO,GACV,OAAO,CAAC,QAAQ,CAAC,CA8DnB"}
|
package/dist/commands/embed.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ApiError } from "../api/errors.js";
|
|
|
3
3
|
import { assertSurface, fetchCatalog, SurfaceMismatchError, } from "../api/models.js";
|
|
4
4
|
import { ExitCode } from "../output/exit-codes.js";
|
|
5
5
|
import { writeOutputFile } from "../output/write-file.js";
|
|
6
|
-
import { buildRuntime, reportError, requireApiKey, } from "./runtime.js";
|
|
6
|
+
import { buildRuntime, reportError, writeHumanError, requireApiKey, } from "./runtime.js";
|
|
7
7
|
const USAGE = `Usage:
|
|
8
8
|
mafdet embed [text | <file>] --model <id> [--output <file>] [--force]
|
|
9
9
|
|
|
@@ -62,7 +62,7 @@ export async function embedCommand(argv, io) {
|
|
|
62
62
|
}
|
|
63
63
|
catch (error) {
|
|
64
64
|
if (error instanceof SurfaceMismatchError) {
|
|
65
|
-
io
|
|
65
|
+
writeHumanError(io, `mafdet embed: ${error.message}\n`);
|
|
66
66
|
return ExitCode.Usage;
|
|
67
67
|
}
|
|
68
68
|
return reportError(error, io);
|
|
@@ -38,7 +38,22 @@ export declare function requireApiKey(config: LoadedConfig): void;
|
|
|
38
38
|
* prints a raw upstream message: ApiError redacted it at construction.
|
|
39
39
|
*/
|
|
40
40
|
/**
|
|
41
|
-
*
|
|
41
|
+
* W-2 · The one function every human-readable stderr write goes through.
|
|
42
|
+
*
|
|
43
|
+
* `reportError` was described as that and was not: `embed` and `speech`
|
|
44
|
+
* handled SurfaceMismatchError themselves, the agent's summary printed
|
|
45
|
+
* `report.error` directly, and even inside `reportError` the request id was
|
|
46
|
+
* concatenated outside the sanitiser. Three real command paths and one field,
|
|
47
|
+
* all carrying remote text to a terminal.
|
|
48
|
+
*
|
|
49
|
+
* The test that was supposed to cover this called `reportError` directly -
|
|
50
|
+
* the callee - and so passed while every caller bypassed it. That mistake has
|
|
51
|
+
* now been made twice; the way out is a function that is easier to use than
|
|
52
|
+
* `io.stderr` is, so there is nothing to remember.
|
|
53
|
+
*/
|
|
54
|
+
export declare function writeHumanError(io: CommandIo, text: string): void;
|
|
55
|
+
/**
|
|
56
|
+
* V-2 · The one place *thrown* errors reach a person.
|
|
42
57
|
*
|
|
43
58
|
* Every command funnels through here, so this is where untrusted text in an
|
|
44
59
|
* error message stops being able to drive the terminal. Patching the
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/commands/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,YAAY,CAAC;IACrB,sCAAsC;IACtC,SAAS,EAAE,UAAU,CAAC;IACtB,yCAAyC;IACzC,YAAY,EAAE,UAAU,CAAC;CAC1B;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAgBnD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CASxD;AAED;;;GAGG;AACH;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,GAAG,QAAQ,CAqBnE"}
|
|
1
|
+
{"version":3,"file":"runtime.d.ts","sourceRoot":"","sources":["../../src/commands/runtime.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAClE,OAAO,EAAE,UAAU,EAAE,MAAM,gBAAgB,CAAC;AAE5C,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAGnD,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,uDAAuD;IACvD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,OAAO;IACtB,MAAM,EAAE,YAAY,CAAC;IACrB,sCAAsC;IACtC,SAAS,EAAE,UAAU,CAAC;IACtB,yCAAyC;IACzC,YAAY,EAAE,UAAU,CAAC;CAC1B;AAED,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAGjD;AAED,wBAAgB,YAAY,CAAC,EAAE,EAAE,SAAS,GAAG,OAAO,CAgBnD;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,YAAY,GAAG,IAAI,CASxD;AAED;;;GAGG;AACH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAIjE;AAED;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,SAAS,GAAG,QAAQ,CAqBnE"}
|
package/dist/commands/runtime.js
CHANGED
|
@@ -39,7 +39,24 @@ export function requireApiKey(config) {
|
|
|
39
39
|
* prints a raw upstream message: ApiError redacted it at construction.
|
|
40
40
|
*/
|
|
41
41
|
/**
|
|
42
|
-
*
|
|
42
|
+
* W-2 · The one function every human-readable stderr write goes through.
|
|
43
|
+
*
|
|
44
|
+
* `reportError` was described as that and was not: `embed` and `speech`
|
|
45
|
+
* handled SurfaceMismatchError themselves, the agent's summary printed
|
|
46
|
+
* `report.error` directly, and even inside `reportError` the request id was
|
|
47
|
+
* concatenated outside the sanitiser. Three real command paths and one field,
|
|
48
|
+
* all carrying remote text to a terminal.
|
|
49
|
+
*
|
|
50
|
+
* The test that was supposed to cover this called `reportError` directly -
|
|
51
|
+
* the callee - and so passed while every caller bypassed it. That mistake has
|
|
52
|
+
* now been made twice; the way out is a function that is easier to use than
|
|
53
|
+
* `io.stderr` is, so there is nothing to remember.
|
|
54
|
+
*/
|
|
55
|
+
export function writeHumanError(io, text) {
|
|
56
|
+
io.stderr(safeForTerminal(text, io.isErrTty ?? process.stderr.isTTY === true));
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* V-2 · The one place *thrown* errors reach a person.
|
|
43
60
|
*
|
|
44
61
|
* Every command funnels through here, so this is where untrusted text in an
|
|
45
62
|
* error message stops being able to drive the terminal. Patching the
|
|
@@ -49,20 +66,22 @@ export function requireApiKey(config) {
|
|
|
49
66
|
* Redirected stderr keeps the bytes, the same rule as everywhere else.
|
|
50
67
|
*/
|
|
51
68
|
export function reportError(error, io) {
|
|
52
|
-
const safe = (text) => safeForTerminal(text, io.isErrTty ?? process.stderr.isTTY === true);
|
|
53
69
|
if (error instanceof ApiError) {
|
|
70
|
+
// W-2 · The request id comes from a response header
|
|
71
|
+
// (`x-litellm-call-id`), so it is remote text too - it used to be
|
|
72
|
+
// concatenated outside the sanitiser.
|
|
54
73
|
const id = error.requestId ? ` (request ${error.requestId})` : "";
|
|
55
|
-
io
|
|
74
|
+
writeHumanError(io, `mafdet: ${error.message}${id}\n`);
|
|
56
75
|
if (error.kind === "rate_limited" &&
|
|
57
76
|
error.retryAfterSeconds !== undefined) {
|
|
58
|
-
io
|
|
77
|
+
writeHumanError(io, `mafdet: retry after ${error.retryAfterSeconds}s\n`);
|
|
59
78
|
}
|
|
60
79
|
return error.exitCode;
|
|
61
80
|
}
|
|
62
81
|
if (error instanceof ConfigError) {
|
|
63
|
-
io
|
|
82
|
+
writeHumanError(io, `mafdet: ${error.message}\n`);
|
|
64
83
|
return ExitCode.Usage;
|
|
65
84
|
}
|
|
66
|
-
io
|
|
85
|
+
writeHumanError(io, `mafdet: ${error.message}\n`);
|
|
67
86
|
return ExitCode.General;
|
|
68
87
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"speech.d.ts","sourceRoot":"","sources":["../../src/commands/speech.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,
|
|
1
|
+
{"version":3,"file":"speech.d.ts","sourceRoot":"","sources":["../../src/commands/speech.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAEnD,OAAO,EAKL,KAAK,SAAS,EACf,MAAM,cAAc,CAAC;AAStB,MAAM,WAAW,QAAS,SAAQ,SAAS;IACzC,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;CACnC;AAED,wBAAsB,aAAa,CACjC,IAAI,EAAE,SAAS,MAAM,EAAE,EACvB,EAAE,EAAE,QAAQ,GACX,OAAO,CAAC,QAAQ,CAAC,CAyEnB"}
|
package/dist/commands/speech.js
CHANGED
|
@@ -3,7 +3,7 @@ import { ApiError } from "../api/errors.js";
|
|
|
3
3
|
import { assertSurface, fetchCatalog, SurfaceMismatchError, } from "../api/models.js";
|
|
4
4
|
import { ExitCode } from "../output/exit-codes.js";
|
|
5
5
|
import { writeOutputFile } from "../output/write-file.js";
|
|
6
|
-
import { buildRuntime, reportError, requireApiKey, } from "./runtime.js";
|
|
6
|
+
import { buildRuntime, reportError, writeHumanError, requireApiKey, } from "./runtime.js";
|
|
7
7
|
const USAGE = `Usage:
|
|
8
8
|
mafdet speech [text | <file>] --model <id> --output <file> [--voice <name>] [--force]
|
|
9
9
|
|
|
@@ -69,7 +69,7 @@ export async function speechCommand(argv, io) {
|
|
|
69
69
|
}
|
|
70
70
|
catch (error) {
|
|
71
71
|
if (error instanceof SurfaceMismatchError) {
|
|
72
|
-
io
|
|
72
|
+
writeHumanError(io, `mafdet speech: ${error.message}\n`);
|
|
73
73
|
return ExitCode.Usage;
|
|
74
74
|
}
|
|
75
75
|
// The gateway requires a voice for TTS and says so with a code; turn that
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/sessions/usage.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,gEAAgE;IAChE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,yEAAyE;IACzE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAC1E,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,WAAW,GAAG;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;CAC3E;
|
|
1
|
+
{"version":3,"file":"usage.d.ts","sourceRoot":"","sources":["../../src/sessions/usage.ts"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE9C,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,GAAG,SAAS,CAAC;AAEjE,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B;;;;OAIG;IACH,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAC;IACnC,gEAAgE;IAChE,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,gBAAgB,EAAE,MAAM,CAAC,CAAC,CAAC;CACnE;AAED,MAAM,WAAW,cAAe,SAAQ,WAAW;IACjD,8EAA8E;IAC9E,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,yEAAyE;IACzE,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG;QAAE,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;IAC1E,QAAQ,CAAC,KAAK,EAAE,SAAS,CAAC,WAAW,GAAG;QAAE,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC,EAAE,CAAC;CAC3E;AA6GD,wBAAgB,cAAc,CAAC,MAAM,EAAE,SAAS,WAAW,EAAE,GAAG,cAAc,CA6D7E;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,WAAW,GAAG,MAAM,GAAG,SAAS,CAcrE"}
|
package/dist/sessions/usage.js
CHANGED
|
@@ -76,8 +76,17 @@ function settlementsIn(events) {
|
|
|
76
76
|
}
|
|
77
77
|
return found;
|
|
78
78
|
}
|
|
79
|
+
/**
|
|
80
|
+
* W-3 · A token count is a non-negative whole number, or it is not a count.
|
|
81
|
+
*
|
|
82
|
+
* `Number.isFinite` accepted -5 and 1.5, so a transcript written by an older
|
|
83
|
+
* build - or by a gateway having a bad day - could produce a negative or
|
|
84
|
+
* fractional total in `sessions usage`.
|
|
85
|
+
*/
|
|
79
86
|
function count(value) {
|
|
80
|
-
return typeof value === "number" && Number.
|
|
87
|
+
return typeof value === "number" && Number.isSafeInteger(value) && value >= 0
|
|
88
|
+
? value
|
|
89
|
+
: 0;
|
|
81
90
|
}
|
|
82
91
|
/** Was this request priced at all? Absent is not the same as zero. */
|
|
83
92
|
function isPriced(value) {
|