Add src/mitm/inspector/pricing.ts with a 10-entry USD/1M-token table and
estimateCost() helper. Wire it into extractLlmMetadata() replacing the
hardcoded null. Tests: 11 new in inspector-pricing.test.ts + 4 new
assertions in inspector-llm-metadata.test.ts (25 pass total).
recordRequestStart() now performs a cheap DB lookup (isCustomHost) before
building the InterceptedRequest. Hosts registered in inspector_custom_hosts
with enabled=1 receive source="custom-host" and agent=undefined, so they
appear correctly under the "Custom" profile filter instead of being
silently routed to "agent-bridge" entries.
Added isCustomHost() helper to inspectorCustomHosts.ts and a unit test
covering enabled custom-host, non-custom host, and disabled custom-host cases.
Wires the previously-dead appendSessionRequest() DB function to a new
POST /api/tools/traffic-inspector/sessions/[id]/requests route.
appendSessionRequest now returns the inserted seq so callers can confirm order.
InspectorSessionRequestAppendSchema (1 MB cap) guards the endpoint.
Integration test covers seq increments 1-2-3, requestCount sync, 400/404 paths,
and stack-trace-free error responses.
The round-3 C1 fix added `server.on("connect", ...)` to satisfy plan 11 §4.6's
text. R4 architectural review confirmed the handler is essentially dead code
on port 443: `https.Server` runs the HTTP parser ABOVE TLS, so a
`server.on("connect")` handler only fires for CONNECT-tunneled-inside-TLS
(HTTPS-proxy-tunneled-in-TLS), not for the "no config required" AgentBridge
DNS-spoof flow where the IDE opens TLS directly to 127.0.0.1:443. Passthrough
for unmapped hosts is structurally handled elsewhere (DNS scoping for default
mode; httpProxyServer.ts:8080 for System-wide proxy mode). Genuine on-wire
bypass-without-decrypt at :443 under direct TLS would require SNI sniffing on
the raw 'connection' event — intentionally out of scope for this release.
This commit:
- adds a block comment above the CONNECT handler explaining the real scope
so future contributors don't assume it covers the primary AgentBridge flow
- guards the `connection` listener with `socket.__mitmCounted` so the
CONNECT "target" branch's `server.emit("connection", clientSocket)`
re-entry doesn't double-increment `stats.activeConnections`
- adds 2 source-grep regression tests asserting both the doc comment and
the guard remain in place
C2 (x-omniroute-source/agent headers) was already correct and is unchanged.
Round-3 F-I18N covered ConversationTab, StatsTab, StatsCharts, and labels in
TimingWaterfall, but missed:
- TimingTab.tsx — 5 user-visible labels (Timestamp, Method, Status, Request
size, Response size) were hardcoded English.
- TimingWaterfall.tsx — empty state ("No timing data available.") and Total
latency label were also hardcoded.
- common.understand — RiskNoticeModal calls
`useTranslations("common")("understand")` but the key did not exist;
only the `|| "I understand"` fallback rescued it, leaving pt-BR users
seeing English.
Adds the missing 7 trafficInspector.timing* keys and common.understand to both
en.json and pt-BR.json, wires `useTranslations` in both components, and adds a
source-grep test asserting no English literals remain in JSX and that all 8
keys exist in both locales.
`Button.tsx` exposes only a default export, but `RiskNoticeModal.tsx` was
importing `{ Button }` (named) — so `Button` resolved to `undefined` and every
render of the modal crashed with React's "Element type is invalid".
The modal opens on first DNS activation for every agent, so this bug
effectively broke DNS interception for every agent in production. It went
undetected through 3 rounds of code review because two test artifacts masked
the failure:
1. `tests/unit/ui/agent-card.test.tsx > calls onDnsToggle when DNS button
clicked` failed since round 3 with the exact error "Element type is
invalid... Check the render method of RiskNoticeModal", but was repeatedly
dismissed as "pre-existing / flaky".
2. `tests/unit/ui/agent-card-risk-modal.test.tsx` (rodada 3) mocked Button
as a named export — which made the test green even though the production
import was broken. Classic "test alignment to broken code" anti-pattern.
This commit:
- switches RiskNoticeModal to `import Button from "@/shared/components/Button"`
- adds a regression-guard test that source-greps for the default-import shape
and asserts Button.tsx remains default-only
- updates the named mock in agent-card-risk-modal.test.tsx to `default:` so
tests now reflect the real module shape (no more masking)
- updates the agent-card.test.tsx DNS-click test to seed the per-agent
risk-accepted localStorage flag, isolating the DNS-toggle path from the
risk-modal path (the modal flow is covered by the risk-modal spec)
After: agent-card.test.tsx 4/4 green; agent-card-risk-modal.test.tsx 5/5 green;
new regression guard prevents recurrence of either pattern.
- mitm-proxy-moved-page.test.tsx: 4 tests — banner renders pageMoved.title/message, goNow triggers router.replace, setTimeout auto-redirect fires at 2500ms
- agent-bridge-server-card-a11y.test.tsx: source-inspection tests for all 6 aria-label attributes in AgentBridgeServerCard + 2 for SessionRecorderBar
- conversation-tab-separators.test.tsx: +1 test that conversationNotAvailable key resolves when body is null
- Add `snapshotSession(sessionId)` to inspectorSessions.ts per master-plan §3.8:
returns parsed InterceptedRequest[] in seq order, or null for non-existent sessions.
Silently skips rows that fail InterceptedRequestSchema validation (defensive).
- Restore canonical no-arg form of `MitmHandlerBase.hookBufferUpdate(intercepted)`
per master-plan §3.5: when opts is omitted, derive completion fields from
the intercepted object itself (status/responseHeaders/responseBody/responseSize/
*LatencyMs) rather than no-op'ing. Extended opts form preserved for legacy callers.
- Update Zod record() calls in InterceptedRequestSchema to current (key,value) signature.
- Add 3 unit tests for snapshotSession (happy path / non-existent / silent skip).
- Add 2 unit tests for hookBufferUpdate (no-arg form + extended opts form).
Cover the new CJS routing primitives and the bypass-JSON manager write
path so the C1/C2 contracts cannot regress silently.
- `mitm-server-connect.test.ts` (27 tests): exercises the
`_internal/bypass.cjs` shim used by `server.cjs`:
- DEFAULT_BYPASS_PATTERNS shape (≥4 regexes, all RegExp)
- Default bank / gov / okta / auth0 → bypass
- Bypass beats target match (precedence)
- Known target hostname → target
- Unknown hostname → passthrough
- User glob pattern → bypass
- Empty / undefined hostname → passthrough
- Set-vs-Array shape for targetHosts
- Case-insensitive hostname matching
- bypassGlobMatch wildcard semantics + ReDoS-safe linear walk
- parseBypassJson with valid / empty / malformed / wrong-shape inputs
- Spec assertions on server.cjs source — header injection (C2),
sanitizeErrorMessage wrapping (Hard Rule #12), and CONNECT handler
registration (C1). These three guard against future regressions
that would silently re-introduce the bugs the C1/C2 fixes closed.
- `mitm-manager-bypass-json.test.ts` (5 tests): exercises
`writeBypassJson()`:
- Creates the `mitm/` dir + valid JSON file shape
- Empty array roundtrips as empty patterns
- Falls back to `getUserBypassPatterns()` when no arg passed
- Default patterns from the DB are NOT written to the file
- Overwrites prior content
AgentCard.handleRiskAccept was calling markRiskAccepted() before opening the
RiskNoticeModal, which itself writes the same key via dontShowAgainKey on accept.
Remove the redundant markRiskAccepted call and delete the now-unused helper so
RiskNoticeModal (D16) is the sole canonical persistence owner. Add a spy-based
test asserting the key is written exactly once per accept.
11 assertions covering: dynamic import with ssr:false, absence of static
recharts import in StatsTab, absence of the discarded _rechartsPreload
pattern, and presence of recharts exports in StatsCharts.
- mitm-handler-base: hookBufferStart returns InterceptedRequest with
sanitized headers, extractSourceModel parses body.model, writeError
emits JSON with sanitized message (Hard Rule #12).
- mitm-handler-<id>: nine per-agent happy-path tests (antigravity,
kiro, copilot, codex, cursor, zed, claude-code, open-code) exercise
full intercept() with mocked fetch via _mitmHandlerHarness.ts;
asserts mapped model is forwarded and AgentBridge correlation
headers are present. Trae test confirms intercept() rejects with a
structured error.
- mitm-targets-resolve: ALL_TARGETS contains 9 entries; resolveTarget
is case-insensitive and returns null for unknown hosts.
- mitm-targets-route: bypass > target > passthrough precedence
validated against representative hostnames.
- mitm-detection: DETECTORS covers every AgentId; detectAgent never
throws and returns DetectionResult-shaped objects for all probes.
Add qwen3.7-max, mimo-v2-pro, mimo-v2-omni, hy3-preview to the
opencode-go provider. Extend executor tests and model specs.
- Registry now matches live https://opencode.ai/zen/go/v1/models response
(16 models). Previously, four models returned by the upstream API were
absent from the static registry, so requests to them failed model
resolution before reaching the executor.
- qwen3.7-max: inherits defaultContextLength 200000; model spec mirrors
qwen3.6-plus (Bailian multimodal, thinking + tools + vision).
- mimo-v2-pro: spec mirrors mimo-v2-omni (262144 ctx, 131072 maxOut,
tools + vision).
- mimo-v2-omni: registry entry only (spec already present upstream).
- hy3-preview: registry entry only; falls back to __default__ spec.
- All four route to /chat/completions (default openai format), matching
the existing opencode-go executor behavior.
* chore(release): bump version to v3.8.5
* fix(docker): rebuild better-sqlite3 after hardened install (#2772)
Integrated into release/v3.8.5
* ci: build Docker platforms on native runners (#2774)
Integrated into release/v3.8.5
* docs(release): sync v3.8.5 documentation and metadata
Update changelog entries, API reference version, package metadata, and
localized LLM documentation for the 3.8.5 release. Refresh generated
docs source mappings and architecture counts for current executors and
OAuth providers.
* chore(release): bump to v3.8.5 — changelog, docs, version sync
* chore(release): translate Hall of Contributors to English in workflows and changelog
* fix(combos): make target timeout configurable (#2775)
Merge PR #2775 — fix(combos): make target timeout configurable
* feat: fix so restart of server restarts batch jobs instead of failing them (#2755)
Merge PR #2755 — feat: fix so restart of server restarts batch jobs instead of failing them
* chore(release): update changelog with merged PRs notes and credits
* feat(api): add endpoint restrictions for client API keys (#2777)
Merge PR #2777 — feat(api): add endpoint restrictions for client API keys
* chore(release): update changelog with PR #2777 entry and contributor credit
---------
Co-authored-by: Thanet S. <cho.112543@gmail.com>
Co-authored-by: Randi <55005611+rdself@users.noreply.github.com>
Co-authored-by: Markus Hartung <mail@hartmark.se>
Co-authored-by: Jack <5443152+hijak@users.noreply.github.com>