Commit Graph

108 Commits

Author SHA1 Message Date
AdrianoDev a1110c8ecb feat(safety+audit+deploy): consistency_check + audit log file sink + deploy script
ci / ruff lint (push) Failing after 12s
ci / mypy mcp_common (push) Successful in 25s
ci / pytest (push) Successful in 35s
ci / validate compose + Caddyfile (push) Successful in 2m3s
ci / build & push to registry (push) Has been skipped
#2 Env switch safety:
- mcp_common/environment.py: nuova consistency_check() che previene
  switch accidentali a mainnet. Solleva EnvironmentMismatchError se
  resolved=mainnet senza creds["environment"]="mainnet" esplicito,
  o se declared/resolved mismatch. Override via STRICT_MAINNET=false.
- Wirato in app_factory.run_exchange_main al boot.
- 6 nuovi test consistency.

#3 Audit log persistence:
- mcp_common/audit.py: TimedRotatingFileHandler aggiuntivo se env
  AUDIT_LOG_FILE settato. Rotation midnight UTC, retention 30gg
  default (AUDIT_LOG_BACKUP_DAYS). Format JSONL con SecretsFilter.
- docker-compose.prod.yml: bind mount /var/log/cerbero-mcp + env
  AUDIT_LOG_FILE per i 4 servizi exchange (write endpoints).
- 2 nuovi test file sink.

#1 Deploy script:
- scripts/deploy.sh: idempotente, fa docker login + clone/pull repo +
  copia secrets chmod 600 + crea .env + setup audit dir + pull image
  + up + smoke test pubblico HTTPS.
- DEPLOYMENT.md aggiornato: sezioni 2 (script), 3 (safety mainnet),
  4 (audit log query), renumber sezioni successive.

Test: 488/488 verdi.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 09:29:04 +02:00
AdrianoDev 019b7e3298 docs: README + DEPLOYMENT con stato CI/CD funzionante
ci / ruff lint (push) Successful in 14s
ci / mypy mcp_common (push) Successful in 23s
ci / pytest (push) Successful in 30s
ci / validate compose + Caddyfile (push) Successful in 2m2s
ci / build & push to registry (push) Successful in 1m32s
README aggiunge sezione 'CI/CD pipeline' che descrive i 5 job e i tag
image. DEPLOYMENT espande sez. 1 con dettagli runner Gitea (network
gitea_gitea-internal, image runner-images, label ubuntu-latest) e
configurazione secret user-level REGISTRY_TOKEN con scope write:package.
2026-04-29 09:18:30 +02:00
AdrianoDev 2fb7043790 ci: push base image al registry + parametrizza BASE_IMAGE nei service Dockerfile
ci / ruff lint (push) Successful in 13s
ci / mypy mcp_common (push) Successful in 23s
ci / pytest (push) Successful in 29s
ci / validate compose + Caddyfile (push) Successful in 2m0s
ci / build & push to registry (push) Successful in 1m43s
Buildx con driver docker-container non vede image caricate nel daemon
locale. Soluzione: push base come git.tielogic.xyz/adriano/cerbero-mcp/
base:latest e i 6 service Dockerfile usano ${BASE_IMAGE}:${BASE_TAG}
con default "cerbero-base" per dev locale, override CI a path registry.
2026-04-29 09:09:47 +02:00
AdrianoDev 38fd7db259 ci: usa secrets.REGISTRY_TOKEN per docker login (scope write:package)
ci / ruff lint (push) Successful in 14s
ci / mypy mcp_common (push) Successful in 26s
ci / pytest (push) Successful in 32s
ci / validate compose + Caddyfile (push) Successful in 2m24s
ci / build & push to registry (push) Failing after 4m13s
GITEA_TOKEN auto-iniettato non include write:package scope necessario per
push al registry. Serve PAT manuale creato in User Settings → Applications
con scope write:package, salvato come secret repo REGISTRY_TOKEN.
2026-04-29 08:53:31 +02:00
AdrianoDev 9da2e12473 lint: ruff clean services/ (autofix + manual + ignore E741)
ci / ruff lint (push) Successful in 15s
ci / validate compose + Caddyfile (push) Successful in 2m6s
ci / mypy mcp_common (push) Successful in 30s
ci / pytest (push) Successful in 34s
ci / build & push to registry (push) Failing after 47s
- 24 autofix safe (SIM105 contextlib.suppress, F401 unused imports,
  I001 import order, B007 unused loop var, F811 redef, F841 unused).
- 15 unsafe-fix (UP038 X|Y in isinstance, SIM108 ternary, ecc.).
- Manual fix: SIM102 nested if in deribit term_structure, E402 imports
  in test_cot.py + sentiment server.py.
- Ignore E741 (variabili 'l' in list comprehensions deribit/client.py
  — stilistico, non bug).

Tests: 478/478 verdi.
2026-04-29 08:44:12 +02:00
AdrianoDev 910f80c99b ci: setup-python@v5 con 3.13 + curl uv install (setup-uv@v5 non applicava python-version)
ci / mypy mcp_common (push) Successful in 25s
ci / pytest (push) Successful in 33s
ci / validate compose + Caddyfile (push) Successful in 3m35s
ci / build & push to registry (push) Has been skipped
ci / ruff lint (push) Failing after 52s
2026-04-29 08:29:24 +02:00
AdrianoDev fe7a9dd9c0 ci: usa astral-sh/setup-uv@v5 con python-version 3.13 (gestisce uv + Python + cache)
ci / ruff lint (push) Failing after 55s
ci / mypy mcp_common (push) Successful in 24s
ci / pytest (push) Successful in 30s
ci / build & push to registry (push) Has been cancelled
ci / validate compose + Caddyfile (push) Has been cancelled
2026-04-29 08:23:50 +02:00
AdrianoDev 503f7a4b17 ci: install Python 3.13 via uv (runner image ha solo 3.10)
ci / ruff lint (push) Failing after 21s
ci / mypy mcp_common (push) Successful in 32s
ci / pytest (push) Successful in 39s
ci / build & push to registry (push) Has been cancelled
ci / validate compose + Caddyfile (push) Has been cancelled
2026-04-29 08:22:29 +02:00
AdrianoDev 0956283463 ci: runs-on ubuntu-latest (label più stabile)
ci / ruff lint (push) Failing after 37s
ci / mypy mcp_common (push) Successful in 20s
ci / pytest (push) Successful in 30s
ci / validate compose + Caddyfile (push) Failing after 3m40s
ci / build & push to registry (push) Has been cancelled
2026-04-29 08:21:07 +02:00
AdrianoDev 7cc28cd6de ci: install uv via astral script + add to GITHUB_PATH
ci / ruff lint (push) Failing after 6s
ci / mypy mcp_common (push) Failing after 7s
ci / pytest (push) Failing after 6s
ci / validate compose + Caddyfile (push) Failing after 2m27s
ci / build & push to registry (push) Has been cancelled
2026-04-29 08:18:07 +02:00
AdrianoDev b91f843d89 ci: remove probe workflow (runner network issue resolved)
ci / ruff lint (push) Failing after 1m4s
ci / mypy mcp_common (push) Failing after 13s
ci / pytest (push) Failing after 13s
ci / build & push to registry (push) Has been cancelled
ci / validate compose + Caddyfile (push) Has been cancelled
2026-04-29 08:13:50 +02:00
AdrianoDev fd811d0692 ci(probe): minimal workflow per diagnosticare runner shell/tools
ci / ruff lint (push) Failing after 31s
ci / mypy mcp_common (push) Failing after 37s
ci / pytest (push) Failing after 31s
ci / validate compose + Caddyfile (push) Failing after 31s
probe / probe shell + tools (push) Successful in 1s
ci / build & push to registry (push) Has been skipped
2026-04-29 07:58:50 +02:00
AdrianoDev 1fea7d4ea1 ci: install uv via pipx (setup-uv@v3 era skipped da Gitea runner)
ci / ruff lint (push) Failing after 42s
ci / mypy mcp_common (push) Failing after 41s
ci / pytest (push) Failing after 35s
ci / validate compose + Caddyfile (push) Failing after 44s
ci / build & push to registry (push) Has been skipped
2026-04-29 07:54:17 +02:00
AdrianoDev b1aea194ad docs: add COT report tools to README macro section
ci / ruff lint (push) Failing after 39s
ci / mypy mcp_common (push) Failing after 27s
ci / pytest (push) Failing after 33s
ci / validate compose + Caddyfile (push) Failing after 37s
ci / build & push to registry (push) Has been skipped
2026-04-29 00:10:06 +02:00
AdrianoDev 8dfb932c8c feat(mcp-macro): expose COT report tools via MCP endpoint 2026-04-29 00:09:20 +02:00
AdrianoDev dc285daac8 feat(mcp-macro): fetch_cot_extreme_positioning scanner
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-29 00:06:52 +02:00
AdrianoDev 2474445b4c feat(mcp-macro): fetch_cot_disaggregated async fetcher with cache 2026-04-29 00:03:53 +02:00
AdrianoDev 66bcab05f9 feat(mcp-macro): fetch_cot_tff async fetcher with cache 2026-04-29 00:02:06 +02:00
AdrianoDev e206df49e4 feat(mcp-macro): add parse_tff_row + parse_disagg_row Socrata mappers 2026-04-29 00:00:04 +02:00
AdrianoDev bf152d90fd feat(mcp-macro): add compute_percentile + classify_extreme pure helpers 2026-04-28 23:58:38 +02:00
AdrianoDev 201f263c77 feat(mcp-macro): add CFTC contract codes constants for COT report 2026-04-28 23:57:31 +02:00
AdrianoDev 28e77cddee docs(plan): COT report implementation plan (8 tasks TDD)
ci / ruff lint (push) Failing after 33s
ci / mypy mcp_common (push) Failing after 31s
ci / pytest (push) Failing after 43s
ci / validate compose + Caddyfile (push) Failing after 38s
ci / build & push to registry (push) Has been skipped
2026-04-28 23:54:05 +02:00
AdrianoDev ad3f542c0f docs: fix markdown lint COT spec (blanks, table padding, code lang)
ci / ruff lint (push) Failing after 38s
ci / mypy mcp_common (push) Failing after 36s
ci / pytest (push) Failing after 34s
ci / validate compose + Caddyfile (push) Failing after 32s
ci / build & push to registry (push) Has been skipped
2026-04-28 23:51:01 +02:00
AdrianoDev b218ac3a2c docs: spec design COT report per mcp-macro
ci / mypy mcp_common (push) Failing after 33s
ci / ruff lint (push) Failing after 37s
ci / pytest (push) Failing after 28s
ci / validate compose + Caddyfile (push) Failing after 33s
ci / build & push to registry (push) Has been skipped
TFF (gpe5-46if) per equity/financial: ES, NQ, RTY, ZN, ZB, 6E, 6J, DX
Disaggregated (72hh-3qpy) per commodities: CL, GC, SI, HG, ZW, ZC, ZS

3 tool MCP: get_cot_tff, get_cot_disaggregated,
get_cot_extreme_positioning (scanner percentile 5/95).

Pure-logic helper + httpx integration test + ACL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:43:40 +02:00
AdrianoDev c31ee0a121 ci: usa astral-sh/setup-uv@v3 (cache integrato, no curl|sh fragile)
ci / ruff lint (push) Failing after 55s
ci / pytest (push) Failing after 32s
ci / validate compose + Caddyfile (push) Failing after 32s
ci / build & push to registry (push) Has been skipped
ci / mypy mcp_common (push) Failing after 31s
2026-04-28 23:39:17 +02:00
AdrianoDev a2fdca3afd ci: clean runs-on syntax (runner stabile post crash-loop fix)
ci / ruff lint (push) Failing after 42s
ci / mypy mcp_common (push) Failing after 27s
ci / pytest (push) Failing after 32s
ci / validate compose + Caddyfile (push) Failing after 30s
ci / build & push to registry (push) Has been skipped
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:24:33 +02:00
AdrianoDev eec1c11cb3 ci: try array syntax runs-on
ci / ruff lint (push) Failing after 29s
ci / mypy mcp_common (push) Failing after 27s
ci / pytest (push) Failing after 29s
ci / validate compose + Caddyfile (push) Failing after 34s
ci / build & push to registry (push) Has been skipped
2026-04-28 23:23:51 +02:00
AdrianoDev 05b431c9c1 ci: try ubuntu-22.04 label
ci / ruff lint (push) Failing after 40s
ci / pytest (push) Failing after 33s
ci / mypy mcp_common (push) Failing after 29s
ci / validate compose + Caddyfile (push) Failing after 34s
ci / build & push to registry (push) Has been skipped
2026-04-28 23:19:59 +02:00
AdrianoDev 59ae9687c8 ci: runs-on tielogic-ci (label specifica del runner registrato)
ci / ruff lint (push) Failing after 1m11s
ci / mypy mcp_common (push) Failing after 26s
ci / pytest (push) Failing after 36s
ci / validate compose + Caddyfile (push) Failing after 1m56s
ci / build & push to registry (push) Has been cancelled
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:17:43 +02:00
AdrianoDev 65641a7de8 ci: validate-config job + cache registry-based
ci / ruff lint (push) Has been cancelled
ci / mypy mcp_common (push) Has been cancelled
ci / pytest (push) Has been cancelled
ci / validate compose + Caddyfile (push) Has been cancelled
ci / build & push to registry (push) Has been cancelled
- Nuovo job validate-config: docker compose -f docker-compose.{yml,prod.yml}
  config -q (verifica sintassi YAML + variabili env) + caddy validate
  --config Caddyfile (sintassi gateway).
- build-and-push ora needs anche validate-config: niente push image se
  compose o Caddyfile sono rotti.
- Cache Docker buildx passata da type=gha (richiede backend cache server
  Gitea Actions configurato) a type=registry,ref=<prefix>/buildcache:<name>
  che usa il registry stesso come storage cache. Funziona out-of-the-box,
  niente setup extra.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 23:02:17 +02:00
AdrianoDev c251fda886 feat(ci/cd): Gitea Actions + registry + Watchtower auto-update
ci / ruff lint (push) Failing after 1m37s
ci / mypy mcp_common (push) Has been cancelled
ci / pytest (push) Has been cancelled
ci / build & push to registry (push) Has been cancelled
CI pipeline (.gitea/workflows/ci.yml):
- Job lint (ruff), typecheck (mypy mcp_common gating + servizi
  warn-only), test (pytest 455).
- Job build-and-push solo su main: builda gateway + 6 image MCP via
  docker/build-push-action@v6, login al registry Gitea con
  docker/login-action@v3 + secrets.GITEA_TOKEN auto-iniettato.
- Cache distribuita type=gha per layer Docker → run successivi 5-10x
  più veloci. Tag :latest + :sha-XXXXXXX per ogni image.

Deploy VPS (docker-compose.prod.yml):
- Niente build locale: solo `image:` da git.tielogic.xyz/adriano/
  cerbero-mcp/<service>:latest. Variabile IMAGE_TAG per pin a sha
  specifico.
- Servizio Watchtower containerizzato che polla ogni 5min (configurabile
  via WATCHTOWER_POLL_INTERVAL) e auto-aggiorna i container con label
  com.centurylinklabs.watchtower.enable=true. Auth registry riusa
  ~/.docker/config.json bind-mounted readonly.

DEPLOYMENT.md: runbook completo per setup VPS, login registry, secrets,
.env, smoke test post-deploy, rollback (pin a sha), disable auto-update,
nota Traefik upload limit. README aggiornato con link.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 22:52:40 +02:00
AdrianoDev 6b7b3f7658 chore: httpx retry transport + healthcheck stdlib + mypy config
- mcp_common/http.py: nuovo helper async_client() con
  AsyncHTTPTransport(retries=3) per gestire connection error transient
  + call_with_retry() generic async retry decorator. Sostituite 25
  occorrenze httpx.AsyncClient(...) in deribit/hyperliquid/sentiment/
  macro client. 5 nuovi test.

- Dockerfile healthcheck: passato da python+httpx subprocess a
  stdlib urllib.request.urlopen() su tutti i 6 servizi MCP. Zero
  dipendenze esterne nel runtime check, timeout esplicito 3s, image
  leggermente più snella.

- pyproject.toml: aggiunto [tool.mypy] python_version=3.13 con
  mypy_path multi-package + override ignore_missing_imports per i
  vendor SDK (pybit, alpaca, hyperliquid, pythonjsonlogger). mypy 1.20
  in dev deps; ruff pinned 0.5.x. mcp_common passa mypy clean; 44
  errori tipo pre-esistenti nei servizi affiorati ma non bloccanti —
  fix da pianificare separatamente.

- 455 test verdi.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 07:26:17 +02:00
AdrianoDev 4d9db750be chore: ruff py313, conftest unification, audit log, app factory comune
- pyproject.toml: ruff target-version py311 → py313 (auto-fix 42 lint
  warnings via UP rules); aggiunto consider_namespace_packages = true
  che risolve la collisione conftest tra servizi e permette di lanciare
  pytest sull'intera suite cross-servizio.

- mcp_common.audit: nuovo helper audit_write_op() con logger dedicato
  mcp.audit. Wirato su tutti i write endpoint di deribit, bybit, alpaca
  e hyperliquid (place_order, place_combo_order, cancel_*, set_*,
  close_*, transfer_*, switch_*, amend_*) con principal + target +
  payload non-sensibile + result summarizzato.

- mcp_common.app_factory: ExchangeAppSpec + run_exchange_main()
  centralizza il boilerplate dei __main__.py (configure_root_logging,
  fail_fast_if_missing, summarize, load creds, resolve_environment,
  load token store, uvicorn). I 4 __main__.py exchange ridotti da ~60
  LOC ognuno a ~25 LOC dichiarativi. mcp_common.env_validation
  promosso da mcp_deribit (mantenuto re-export shim per back-compat
  test_env_validation).

- 8 test nuovi (4 audit + 4 app_factory). Suite full: 450/450 verdi.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-28 00:27:02 +02:00
AdrianoDev a13e3fe045 feat: 15 nuovi indicatori quant (common + deribit + bybit + macro + sentiment)
Common (mcp_common):
- indicators.py: vol_cone, hurst_exponent, half_life_mean_reversion,
  garch11_forecast, autocorrelation, rolling_sharpe, var_cvar
- options.py (nuovo): oi_weighted_skew, smile_asymmetry, atm_vs_wings_vol,
  dealer_gamma_profile, vanna_charm_aggregate
- microstructure.py (nuovo): orderbook_imbalance (ratio + microprice + slope)
- stats.py (nuovo): cointegration_test Engle-Granger + ADF helper

Deribit (+6 tool MCP):
- get_dealer_gamma_profile (net dealer gamma + flip level)
- get_vanna_charm (vanna/charm aggregati pesati OI)
- get_oi_weighted_skew, get_smile_asymmetry, get_atm_vs_wings_vol
- get_orderbook_imbalance

Bybit (+2 tool MCP):
- get_orderbook_imbalance, get_basis_term_structure (futures dated curve)

Macro (+2 tool MCP):
- get_yield_curve_slope (2y10y/5y30y + butterfly + regime)
- get_breakeven_inflation (FRED T5YIE/T10YIE/T5YIFR)

Sentiment (+3 tool MCP):
- get_funding_arb_spread (opportunità arb compatte annualizzate)
- get_liquidation_heatmap (heuristic da OI delta + funding extreme,
  no feed paid Coinglass)
- get_cointegration_pairs (Engle-Granger su coppie crypto Binance hourly)

Tutto in TDD pure-Python (no numpy/scipy in mcp_common). README
aggiornato con elenco completo. 442 test totali verdi.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:58:07 +02:00
AdrianoDev 867180f4bf feat(gateway): TLS auto + rate limit + IP allowlist su write endpoint
Configura il gateway Caddy per il deploy su cerbero-mcp.tielogic.xyz:

- Build custom Caddy con plugin mholt/caddy-ratelimit (Dockerfile +
  build via xcaddy).
- TLS automatico via Let's Encrypt (richiede DNS A record + porte
  80/443 raggiungibili), HSTS preload, header di sicurezza.
- Rate limit per IP (60 req/min sui read, 10 req/min sui write,
  sliding window).
- Allowlist IP sui write endpoint (place_*, cancel_*, set_*, close_*,
  transfer_*, amend_*, switch_*): IP non in WRITE_ALLOWLIST → 403.
- Default WRITE_ALLOWLIST copre loopback + Docker bridge: bot sulla
  stessa macchina (host o container) funziona senza configurazione,
  IP pubblici esterni vanno aggiunti esplicitamente.
- Smoke test e README aggiornati per il nuovo URL gateway.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:24:06 +02:00
AdrianoDev c2fd8330ca feat(mcp-deribit,mcp-bybit): add place_combo_order
Deribit: private/create_combo + place_order sul combo instrument → una
sola crociata di spread invece di N (slippage atteso ridotto su
strutture liquide). ACL core + leverage cap su tutti i leg.

Bybit: place_batch_order su category=option (atomic multi-leg, 1
round-trip API). Reject su category != option (perp/linear non
supportano batch nativo). orderLinkId auto-generato per leg.

Tutti i test: deribit 48/48, bybit 123/123.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 23:12:09 +02:00
AdrianoDev bacd5aab33 docs: aggiornati README e smoke con live checks + resolver kwargs
Documentata la precedenza di risoluzione environment e l'utilizzo dei
nuovi kwargs default_base_url_live/testnet di resolve_environment.
Smoke README estesa con i 6 live tool check read-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:29:46 +02:00
AdrianoDev 21da74e8a1 refactor(mcp-common): centralize base_url defaults in resolve_environment
Aggiunti kwargs opzionali default_base_url_live / default_base_url_testnet
a resolve_environment. Rimosse 8 chiamate creds.setdefault duplicate dai
4 servizi (alpaca, bybit, deribit, hyperliquid) ora passano gli URL
canonici direttamente al resolver.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-27 22:28:18 +02:00
AdrianoDev 81fb5e8c29 test(smoke): aggiunti live tool check read-only su 6 MCP 2026-04-27 22:11:47 +02:00
AdrianoDev 1dbf9bbd7b fix(mcp-bybit): wire creds + env_info into create_app (was missing) 2026-04-27 21:39:25 +02:00
AdrianoDev d1cea403a7 fix(docker/base): rename package option-mcp-common → mcp-common 2026-04-27 21:36:21 +02:00
AdrianoDev 33f358c13a test(smoke): bash + curl + jq script per i 6 MCP 2026-04-27 21:35:48 +02:00
AdrianoDev de19d42850 feat(mcp-alpaca): leverage_cap + paper resolver + environment_info 2026-04-27 17:57:17 +02:00
AdrianoDev fb8c43cc61 feat(mcp-hyperliquid): leverage_cap + testnet resolver + environment_info 2026-04-27 17:55:26 +02:00
AdrianoDev e958422fe5 feat(mcp-bybit): leverage_cap + testnet resolver + environment_info 2026-04-27 17:53:07 +02:00
AdrianoDev 0b471f207a feat(mcp-deribit): testnet resolver + environment_info tool + env override 2026-04-27 17:50:48 +02:00
AdrianoDev ecb2d0e4c2 refactor(mcp-deribit): replace risk_guard with local leverage_cap 2026-04-27 17:49:35 +02:00
AdrianoDev a163947205 feat(mcp-deribit): leverage_cap module with TDD 2026-04-27 17:46:54 +02:00
AdrianoDev b16b26e2e3 refactor(mcp-deribit): localize env_validation as service-internal util 2026-04-27 17:45:08 +02:00
AdrianoDev 37e5024acc feat(mcp_common): add environment.resolve_environment with TDD 2026-04-27 17:39:52 +02:00