Commit Graph

3012 Commits

Author SHA1 Message Date
oyi77
8669bf69ec feat(ui): add InfoTooltip and PresetSlider shared components 2026-05-17 05:33:27 +07:00
diegosouzapw
7e9efe7cb0 chore(changelog): add missing entries #2283, #2284, #2285, #2279, #2228 and translate PT→EN 2026-05-16 19:24:48 -03:00
diegosouzapw
bbfd3865a5 chore(changelog): update for PRs #2313, #2312, #2309 2026-05-16 17:42:35 -03:00
Markus Hartung
dae0501d75 fix: remove count from batch removal (#2309)
Integrated into release/v3.8.0
2026-05-16 17:39:50 -03:00
Mourad Maatoug
8eb721ec31 fix(claude): guard orphan tool_use/tool_result pairs before upstream send (#2312)
Integrated into release/v3.8.0
2026-05-16 17:39:47 -03:00
backryun
ebef1648be chore: Imporve cohere provider support (#2313)
Integrated into release/v3.8.0
2026-05-16 17:39:44 -03:00
diegosouzapw
f80de415ec docs(changelog): add entry for PR #2308
- Add auth+build fix entry to [Unreleased]
- Update @mrmm PR count (2 -> 3)
2026-05-16 13:29:50 -03:00
Mourad Maatoug
ec138c6fee fix(auth+build): Bearer manage scope on management routes + lazy-load deepseek PoW solver (#2308)
Integrated into release/v3.8.0
2026-05-16 13:28:57 -03:00
josephvoxone
04335c5a6b fix: remove implicit API key request caps (#2289)
Conflicts resolved and integrated into release/v3.8.0. Thanks again!
2026-05-16 12:12:53 -03:00
diegosouzapw
c15ea65a26 docs(changelog): add entry for PR #2305
- Add v3.8.0 ui polish fixes entry to [Unreleased]
- Update @mrmm PR count (1 -> 2)
2026-05-16 12:07:00 -03:00
Mourad Maatoug
2af6923e6e fix(ui): v3.8.0 polish — connections border, sticky tabs, EN translations, save toasts, auto-combo catalog (#2305)
Integrated into release/v3.8.0
2026-05-16 12:06:12 -03:00
diegosouzapw
9efad44fc9 docs(changelog): add missing entries for PRs #2286, #2288, #2289, #2290, #2291, #2294, #2295, #2299
- Add 8 missing contributor PR entries to [Unreleased] section
- Add 3 new contributors to the community table:
  @thepigdestroyer (2 PRs), @josephvoxone (1 PR), @mrmm (1 PR)
- Update counts: @oyi77 12→14, @backryun 8→9, @ddarkr 3→4,
  @hartmark 2→4
- Compensates for cherry-picked PRs that couldn't be properly
  merged via GitHub (branch deleted or fork restriction)
2026-05-16 10:52:46 -03:00
diegosouzapw
b3baa0e9f4 docs(changelog): document #2281 #2300 #2298 #2292 fixes 2026-05-16 10:16:33 -03:00
diegosouzapw
56d6ad604c fix(opencode-zen): flag qwen3.6-plus(-free) as targetFormat=claude (#2292)
opencode-zen returns Claude-format SSE bodies (type: 'message_start', no
choices array) for qwen3.6-plus and qwen3.6-plus-free even when the request
hits the OpenAI-compatible /chat/completions endpoint. Clients expecting
OpenAI format fail Zod validation with 'expected choices (array), received
undefined'.

Flagging these two models with targetFormat: 'claude' makes the opencode
executor route through /messages and the response is parsed by the Claude
translator. This matches the existing minimax-m2.7/m2.5 pattern in
opencode-zen and is the minimum-risk fix that ships in v3.8.0.

The broader runtime format-detection refactor proposed by @raccoonwannafly
(detect Claude payload on 200 response from OpenAI endpoint) is deferred
to a dedicated PR with end-to-end tests.
2026-05-16 10:15:46 -03:00
diegosouzapw
52222aaf76 fix(embeddings/registry): add DeepInfra to embedding provider registry (#2298)
Custom embedding models on the DeepInfra provider (e.g.
Qwen/Qwen3-Embedding-8B) were rejected by createEmbeddingResponse with
'Unknown embedding provider: deepinfra. No matching hardcoded or local
provider found.' because the registry only included Nebius/OpenAI/Together/
Fireworks/NVIDIA/Mistral/Voyage/Jina/Gemini. The fallback to
provider_nodes only resolves localhost/172.x dev URLs, so remote DeepInfra
keys had no path to /v1/embeddings.

Adds DeepInfra with 8 popular embedding models (Qwen3-Embedding-8B/4B/0.6B,
BGE Large/Base/M3, E5 Large v2, GTE Large) routed through
https://api.deepinfra.com/v1/openai/embeddings.

Part 1 (incomplete model list import) still needs reproduction details
from the reporter and will be tracked separately.
2026-05-16 10:14:57 -03:00
diegosouzapw
124ed82f02 fix(api/combos): add API-key-safe GET /v1/combos endpoint (#2300)
The existing /api/combos GET requires a management token, which broke
read-only integrations (opencode-omniroute-auth plugin and similar) that
need to enrich combo capabilities from a normal Bearer API key. Those
clients got 403 AUTH_001 'Invalid management token' even though the same
API key could list models via /v1/models.

This adds GET /v1/combos with the same auth model as /v1/models:
- Accepts valid Bearer API key OR dashboard session cookie.
- Falls back to anonymous when REQUIRE_API_KEY=false (single-user local).
- Projects ONLY public metadata: name, strategy, description, model id,
  providerId, comboName (for combo-refs). Internal routing details
  (connectionId, weights, labels, sortOrder, config) are stripped.

/api/combos (management writes) is unchanged.
2026-05-16 10:14:06 -03:00
diegosouzapw
50ad3b0e22 fix(translator): map developer→system by default for non-openai providers (#2281)
The OpenAI Responses API path emits 'developer' role messages. The previous
default preserved that role for any targetFormat=openai upstream, which broke
DeepSeek, MiniMax, Mimo, GLM, Fireworks, Together, and most other
OpenAI-compatible gateways with '[400]: unknown variant developer, expected
one of system/user/assistant/tool'.

New default: preserve developer only for the openai-family allowlist
(openai, azure-openai, azure, github, or any id containing 'openai').
Convert developer→system for everyone else when preserveDeveloperRole is
not explicitly set. The dashboard 'Compatibility → preserveOpenAIDeveloperRole
= true' toggle still forces preservation when needed.
2026-05-16 10:13:08 -03:00
Diego Rodrigues de Sa e Souza
3046705c22 Merge pull request #2295 from oyi77/feature/deepseek-web-executor-v2
Integrated into release/v3.8.0
2026-05-16 09:48:19 -03:00
Diego Rodrigues de Sa e Souza
5848fe3948 Merge pull request #2294 from hartmark/fix/migration-version-collisions
Integrated into release/v3.8.0
2026-05-16 09:48:16 -03:00
Diego Rodrigues de Sa e Souza
718637c5cd Merge pull request #2286 from mrmm/mm/issue-2260-cc-bridge-sanitization
Integrated into release/v3.8.0
2026-05-16 09:48:14 -03:00
Diego Rodrigues de Sa e Souza
132658d009 Merge pull request #2290 from thepigdestroyer/fix/remove-dead-claudecode-lowercase-flag
Integrated into release/v3.8.0
2026-05-16 09:48:10 -03:00
diegosouzapw
c9c6c63216 feat(batch): global rate-limit header cache with 60s TTL + 24h retry window (#2299)
- Promote prevHeaders from per-batch local to module-level global with 60s TTL
- Share rate-limit throttle state across sequential batches
- Use 24h time-based retry limit (MAX_RETRY_DURATION_MS) instead of count-only
- Increase baseMs to 5s and maxMs to 1h for batch-appropriate backoff
- Add getCachedHeaders/resetCachedHeaders test helpers
- 7/7 unit tests pass

Authored-by: Markus Hartung <hartmark@users.noreply.github.com>
2026-05-16 09:08:36 -03:00
diegosouzapw
5c41961351 feat(deepseek-web): full DeepSeek web API executor with PoW solver (#2295)
- DeepSeekWebExecutor with ds_session_id cookie auth
- DeepSeekWebWithAutoRefreshExecutor for session management
- Keccak-based PoW solver (DeepSeekHashV1)
- SSE stream transformation to OpenAI format
- Provider constant and alias (ds-web)
- 23 unit tests + live integration test

Authored-by: Paijo <oyi77@users.noreply.github.com>
2026-05-16 00:27:56 -03:00
diegosouzapw
72afecffeb fix(migrations): resolve version collisions and add batch deletion API (#2294)
- Rename 056_provider_connection_quota_window_thresholds.sql to 057
- Add LEGACY_VERSION_SLOT_MIGRATIONS entries for backward compatibility
- Add deleteBatch/deleteCompletedBatches to batches.ts
- Add DELETE routes for batches (single + bulk)
- Add batch deletion buttons to dashboard
- Broaden dashboard session auth to all client API routes
- Add quota_window_thresholds_json column repair

Authored-by: Markus Hartung <hartmark@users.noreply.github.com>
2026-05-16 00:27:20 -03:00
diegosouzapw
5221a81a75 feat(cc-bridge): config-driven per-provider system-block transform DSL (#2286, closes #2260)
Authored-by: Paijo <oyi77@users.noreply.github.com>
2026-05-16 00:26:25 -03:00
diegosouzapw
8db3fec05a build(deps): bump actions/checkout from 4 to 6 (#2288)
Authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-16 00:25:54 -03:00
diegosouzapw
baefcd06f0 fix: remove implicit API key request caps (#2289)
Removes default daily/weekly/monthly request caps (1K/5K/20K) that were
silently applied to API keys without explicit rate limits, causing
surprise 429s in production aggregator deployments.

Authored-by: josephvoxone <josephvoxone@users.noreply.github.com>
2026-05-16 00:25:35 -03:00
diegosouzapw
b060ebb05b fix(sse): remove dead-code flag leak in claudeCodeToolRemapper (#2290)
Authored-by: thepigdestroyer <thepigdestroyer@users.noreply.github.com>
2026-05-16 00:25:04 -03:00
diegosouzapw
acc9a8780d fix(sse): strip stale content-encoding/length/transfer-encoding from upstream responses (#2291)
Authored-by: Paijo <oyi77@users.noreply.github.com>
2026-05-16 00:24:13 -03:00
Markus Hartung
15d20b7b59 Fix so we have delete on batches instead of files and fix so delete works 2026-05-16 04:57:56 +02:00
Markus Hartung
35cb91c3a9 More permissive cookie auth so /dashboard/batch works with REQUIRE_API_KEY=true 2026-05-16 03:56:13 +02:00
oyi77
523f674fff feat(deepseek-web): full DeepSeek web API executor with PoW solver
Adds a complete executor for DeepSeek's native web API with:

- Authentication via ds_session_id cookie → Bearer token from /users/current
- Proof-of-Work (DeepSeekHashV1) solver using custom Keccak sponge
- SSE stream response parsing with OpenAI-compatible output
- Web search toggle (search_enabled)
- Deep thinking toggle (thinking_enabled + x-thinking-enabled header)
- File attachment support (ref_file_ids)
- Auto-refresh executor for session management
- 23 unit tests covering all features + live integration test

API flow: /users/current → /chat_session/create → /create_pow_challenge
→ PoW solve → /chat/completion with native DeepSeek body format

Co-Authored-By: OpenClaude (mimo-v2.5-pro) <openclaude@gitlawb.com>
2026-05-16 08:20:59 +07:00
Markus Hartung
7b73ac47da fix(db): add quota_window_thresholds_json to SCHEMA_SQL and in-memory path
- Add missing column to provider_connections CREATE TABLE baseline so
  fresh/in-memory databases include it from the start
- Call ensureProviderConnectionsColumns for in-memory instances to match
  the file-backed path
2026-05-16 01:31:23 +02:00
Mrinal Joshi
07f3b71fc9 style(sse): condense flag-removal NOTE comment (review feedback)
Compresses the explanatory NOTE in claudeCodeToolRemapper.ts from 6 lines
to 4 while keeping the actionable why: the flag has no readers, would
leak into the Anthropic request body causing HTTP 400 (Extra inputs are
not permitted), and the response-side remap is unconditional.

Addresses gemini-code-assist review feedback on PR #2290.
2026-05-16 00:31:03 +01:00
Markus Hartung
8e5c1d9ead fix(migrations): resolve version collisions and add schema repair for quota thresholds 2026-05-16 01:19:39 +02:00
Mourad Maatoug
1daf15efbd feat(ui): optimistic save + per-op descriptions + per-field hints
Fixes 'first-time save silently dropped' when adding a fresh op with
required-but-empty fields (e.g. replace_regex.pattern). Server returns 400
with field-level zod errors; previously the UI never applied the local
edit because setSettings was gated on res.ok. Now:

- updateSetting applies the patch to local state FIRST (optimistic).
- On 400 it surfaces a 'Server rejected save:' banner per provider listing
  each failing field, with copy telling the user their edit is kept.
- Next valid PATCH clears the banner.

Also: every op kind gets an italic description paragraph above its editor,
and every field gets a plain-English hint underneath explaining what it
does and when to use it. Drift-prone refs softened (no 'v1.7.5 ex-machina'
internal jargon, no false 'server validates regex compiles' claim).

59/59 unit tests green; tsc clean.
2026-05-15 23:57:31 +02:00
Mourad Maatoug
b653cfd160 feat(ui): collapsible provider tiles + ops + move Add provider to top
Reduces vertical footprint of the System-block Transform Pipeline card so
long pipelines (cc-bridge ships 9 ops) do not dominate the Routing tab.

- New Collapsible component (src/shared/components/Collapsible.tsx) used as
  a shared primitive. Open/closed state lives in local component state; does
  NOT persist across reloads (per UX brief: always-collapsed default).
- Each provider tile is now collapsible (closed by default).
- Each pipeline op inside a provider is collapsible (closed by default) —
  click to expand the per-kind editor.
- 'Add provider' Select+Button moved from BOTTOM to TOP of the card with a
  dashed border, so it is the first thing the user sees.
- Trailing controls (Toggle, Button) render as siblings of the toggle button
  (not nested), avoiding invalid <button> inside <button> HTML.

59/59 unit tests green.
2026-05-15 23:47:36 +02:00
Mourad Maatoug
79e19b5466 test(system-transforms): UI ↔ server defaults parity snapshot
Hand-maintained DEFAULT_SYSTEM_TRANSFORMS_CLIENT mirror in RoutingTab.tsx
drifts silently from server DEFAULT_SYSTEM_TRANSFORMS_CONFIG. New test asserts
deepEqual against the JSON-shape of the server export and points at the UI
file in the failure message so contributors update both in the same commit.

23/23 green.
2026-05-15 23:43:06 +02:00
Mrinal Joshi
4f01a8995b fix(sse): strip stale content-encoding/length/transfer-encoding from upstream responses
`fetch()` always transparently decompresses the upstream body before
exposing it via `.text()` or the stream reader, so forwarding the
upstream `content-encoding` header (e.g. `gzip`) to the downstream
OpenAI/Anthropic-compatible client makes the client attempt to gunzip
plain text and fail with `ZlibError: incorrect header check`.

Similarly, `content-length` becomes stale once we transform the response
body (non-stream path repacks via `new Response()`; stream path
re-streams through our SSE heartbeat / shape transforms), and
`transfer-encoding` is owned by the Node/Next runtime, not us.

This patch adds `open-sse/utils/upstreamResponseHeaders.ts` exporting:

- `stripStaleEncodingHeaders(input: Headers)` — returns a new `Headers`
  with content-encoding, content-length, transfer-encoding removed
  (case-insensitive, does not mutate input).
- `filterUpstreamResponseHeaderEntries(entries, extraToStrip)` — same
  semantics for the entries-array path used by the streaming response
  builder, plus user-supplied additional names (case-insensitive).
- `STRIP_UPSTREAM_HEADER_NAMES` — the canonical set, exported for tests.

`open-sse/handlers/chatCore.ts` now uses these helpers in two places:

1. Non-stream path (~L3211): replaces `new Headers(rawResult.response.headers)`
   with `stripStaleEncodingHeaders(...)` so the repacked Response below
   doesn't claim a stale encoding/length.
2. Stream path (~L4371): replaces an inline IIFE+filter that only
   removed `content-type` with `filterUpstreamResponseHeaderEntries(...,
   ["content-type"])` so the stale encoding/length are also stripped
   before we set our own `text/event-stream` content-type.

Both call sites carry a comment explaining the underlying fetch
decompression behavior.

Tests
-----

New `tests/unit/upstream-response-headers-strip.test.ts` adds 10 cases
covering: lowercase strip, mixed-case strip, input non-mutation, empty
input, default-set filter, case-insensitive extraToStrip, empty
extraToStrip preservation, empty entries, mixed-case default names, and
canonical set identity.

Verified locally
----------------

- `npx eslint open-sse/utils/upstreamResponseHeaders.ts open-sse/handlers/chatCore.ts tests/unit/upstream-response-headers-strip.test.ts` — clean.
- `npm run typecheck:core` — clean.
- `node --import tsx/esm --test tests/unit/upstream-response-headers-strip.test.ts tests/unit/upstream-headers-sanitize.test.ts tests/unit/chatcore-sanitization.test.ts tests/unit/chat-route-edge-cases.test.ts tests/unit/chatcore-translation-paths.test.ts tests/unit/chatcore-compression-integration.test.ts` — 95/95 pass.
- Full `npm run test:unit` / `test:coverage` deferred to upstream CI
  (122 test files, exceeds local timeout window).
2026-05-15 20:23:53 +01:00
Mrinal Joshi
fa1d1fe7eb fix(sse): remove dead-code flag leak in claudeCodeToolRemapper
remapToolNamesInRequest() set body._claudeCodeRequiresLowercaseToolNames = true
when a request contained only lowercase tool names. The flag had no readers in
src/ or open-sse/ (verified by repo-wide grep) and leaked into the outgoing
Anthropic /v1/messages payload, causing HTTP 400:

  "_claudeCodeRequiresLowercaseToolNames: Extra inputs are not permitted"

The response-side lowercase remap via remapToolNamesInResponse(text, true) is
unconditional and does not depend on this flag, so removing it is a no-op for
the response path while fixing the request path.

Adds tests/unit/claude-code-tool-remapper-flag-leak.test.ts as a regression
guard with 5 cases covering all-lowercase, all-TitleCase, mixed-case, and a
flag-leak sweep across all input shapes.
2026-05-15 20:13:43 +01:00
Mourad Maatoug
a6af54a047 fix(ui): provider dropdown from AI_PROVIDERS catalog + shared Button for op controls
Caveman-review iteration on commit 4fde71a4:

1. Provider selection uses Select dropdown populated from AI_PROVIDERS
   registry (the canonical provider catalog) instead of free-text Input.
   Filters out providers already configured under systemTransforms.providers.
   Drops PROVIDER_ID_PATTERN regex + newProviderError state — dropdown
   makes invalid input impossible.

2. Per-op move-up / move-down / delete buttons now use the shared Button
   component with material icons (keyboard_arrow_up, keyboard_arrow_down,
   delete) + i18n titles, instead of raw <button> with emoji glyphs.
   Matches the rest of the OmniRoute UI.

3. BUILTIN_PROVIDERS Set was being recreated every render inside the
   component body. Moved to module scope.

i18n: added systemTransformsAddProviderAllConfigured, systemTransformsOpMoveUp,
systemTransformsOpMoveDown, systemTransformsOpDelete. Re-purposed
systemTransformsAddProviderPlaceholder as the dropdown's empty-state label
('Select a provider…').

Tests: 58/58 green (cc-bridge-transforms + system-transforms +
claude-code-compatible-helpers).

Refs PR #2286.
2026-05-15 19:05:50 +02:00
Mourad Maatoug
4fde71a4b1 feat(ui): separate system-block transforms into own Card + add/remove any provider
- System-block transform pipeline is now a dedicated Card (was nested
  subsection inside the CLI Fingerprint Matching Card).
- Any provider ID can be added via the 'Add provider' input at the
  bottom of the transforms Card; the new provider starts with
  enabled=false and an empty pipeline.
- Custom (non-builtin) providers have a delete button to remove them.
- Builtin providers (claude, anthropic-compatible-cc) are protected from
  deletion (removeProvider guard).
- Add systemTransforms i18n keys for the new section title, description,
  add-provider label/placeholder, remove label, empty state.
- The CLI Fingerprint Matching Card is now a clean standalone Card.
2026-05-15 18:54:41 +02:00
Mourad Maatoug
149e901514 fix(ui): Claude tile disablable + strip issue refs + clean provider tile copy
- Remove forced=true lock on Claude tile in CLI Fingerprint Matching —
  all providers now equally toggleable.
- Replace hardcoded GitHub issue link (#2260) and 'no local CLI binary
  required' note in card header with clean i18n-keyed description.
- Remove forcedFingerprintTitle + forcedFingerprintBadge i18n keys
  (now unused).
- Clean provider tile descriptions (PROVIDER_TILE_DISPLAY) to remove
  internal implementation detail language.
- Replace internal-jargon system-transforms footnote with user-facing
  note about idempotency.
2026-05-15 18:51:02 +02:00
Mourad Maatoug
69f0735c7a fix(cc-bridge): use idempotencyKey in prepend/append block ops
applyPrependSystemBlock and applyAppendSystemBlock were not using the
idempotencyKey when set — the old check used op.text as the idempotency
prefix and only examined the first/last block.

Fix: scan ALL existing text blocks; use idempotencyKey as prefix when set,
fall back to op.text (prepend) / exact match (append).
2026-05-15 18:39:21 +02:00
Mourad Maatoug
0f656571d5 refactor(system-transforms): use shared UI primitives + drop dead i18n keys
- Replace raw <input>/<select>/<textarea>/<label> in OpEditor with shared
  Input, Select, Toggle components — matches the pattern used by every
  other settings tab in the app.
- New StringListEditor helper consolidates the three list-of-strings
  forms (needles, prefixes, words) into one consistent component.
- Replace the peer-checkbox custom provider-enable toggle with the
  shared Toggle component (same look as Adaptive Volume, LKGP, etc).
- Replace the raw add-op <select> with shared Select.
- Drop nine unused 'ccBridgeTransforms*' i18n keys left over from the
  Phase 2 v1 UI — current UI uses inline strings under the
  'CLI Fingerprint Matching' card.
- Document why systemTransforms keeps its own looser RequestBody shape
  (legacy ccBridgeTransforms RequestBody is stricter; cast at boundary).
2026-05-15 18:32:02 +02:00
Mourad Maatoug
875c8f77c1 feat(system-transforms): per-op UI editor + claude opt-in default + restore section name
- claude provider enabled:false by default (opt-in; was incorrectly true)
- add OpEditor component: per-op form editor for all 9 DSL kinds
  (add/move-up/move-down/delete via UI buttons, JSON editor collapsed)
- rename card back to 'CLI Fingerprint Matching' per user feedback
- JSON import/export now collapsible under '▸ Import / export JSON'
- tests updated to explicitly enable claude provider where pipeline behavior
  is under test (not the opt-in default)
2026-05-15 18:19:48 +02:00
Diego Rodrigues de Sa e Souza
79d03575ee feat(cli): suporte i18n completo — 42 locales, --lang flag, config lang get/set/list (#2285)
feat(cli): suporte i18n completo — 42 locales, --lang flag, config lang get/set/list

- 42 locale files in bin/cli/locales/ (en + pt-BR fully translated, 29 with common/program, 11 scaffolds)
- --lang <code> global flag for per-execution override
- config lang get/set/list subcommands
- Locale persistence via ~/.omniroute/.env
- Path traversal protection via regex validation in normalize()
- Script generate-locales.mjs for scaffolding new locales
- Unit tests for lang commands + normalization security

Integrated into release/v3.8.0
2026-05-15 13:14:14 -03:00
Mourad Maatoug
4d000f1eb0 fix: strip _claudeCodeRequiresLowercaseToolNames before serialization
The sentinel field set by remapToolNamesInRequest() was being included in
the JSON body sent to Anthropic, which rejects unknown top-level fields
with 400 invalid_request_error. Stripped before JSON.stringify in both
code paths:
- buildAndSignClaudeCodeRequest (CC bridge / anthropic-compatible-cc-*)
- base executor serialization path (native claude/ provider)

Pre-existing bug, not introduced by issue #2260 changes.
2026-05-15 18:07:57 +02:00
Mourad Maatoug
d0d8638a02 refactor(system-transforms): caveman-review cleanup + logging
- Remove dead setWordsForOp function (unused, acknowledged in comment)
- Remove unused obfuscateSensitiveWords import and re-export from systemTransforms
- Increase textarea rows cap from 20→40 for long CC-bridge pipelines (~100 lines JSON)
- Add [SystemTransforms] console.log at both call sites (cc-bridge step 5b + claude native path)

Tests: 58/58 green
2026-05-15 17:57:40 +02:00
diegosouzapw
0d09858526 chore: remove junk files from PR #2283 squash merge
- Remove .playwright-mcp/ debug artifacts (accidentally committed)
- Remove duplicate docs/routing/CLI-TOOLS.md (canonical at docs/reference/)
2026-05-15 12:51:28 -03:00