feat(mcp): WS-mode к v8-client-session-manager + skill bootstrap reference - #3
feat(mcp): WS-mode к v8-client-session-manager + skill bootstrap reference#3zeegin wants to merge 15 commits into
Conversation
…layout Anthropic Skills convention: каталог скила = его имя в kebab-case, внутри обязательно SKILL.md + references/. Готовый каталог можно дроп-копировать в ~/.claude/skills/<name>/ без переименования. В этом репо frontmatter скила декларирует name: v8-runner, поэтому каталог приводим в соответствие. Что сделано: - git mv SKILL v8-runner (sохраняет историю) - ссылки обновлены: AGENTS.md (×2), spec/decisions/0022-*.md (×1) После рефакторинга разработчику достаточно сделать cp -r v8-runner ~/.claude/skills/ чтобы скил стал доступен Claude Code.
Adds src/use_cases/mcp_ws with: - McpClientTransport (Ws/Legacy/Auto) selector - ClientKind enum mapping entry-points to manager-side kind values - WsLaunchParams::payload_snippet() that produces the 'mcpMode=ws;manager_url=...;client_uid=...;kind=...;corr_id=...; mcp_log_level=...;mcp_ws_timeout_ms=...' segment for /C - select_transport() with probe-callback (Auto -> WS or Legacy) - probe_tcp() built on std::net::TcpStream::connect_timeout - parse_manager_addr() that extracts host:port from a ws://... URL - validate_log_level() for off|error|warn|info|debug|trace Pure module without project plumbing yet; later commits wire it into launch_app, run_tests, CLI args and config loading.
Adds new optional fields under tools.client_mcp: - transport: ws | legacy | auto - manager_url: ws://host:port/... - log_level: off | error | warn | info | debug | trace - ws_timeout_ms: u64 (>= 1) Reuses tools.client_mcp instead of mcp.client because the loader still rejects mcp.client as a legacy migration guard (LegacyMcpClientConfig). Putting the new keys next to port/extension keeps client-MCP config in one place. Schemas (ClientMcpToolSchema, PartialClientMcpToolSchema) and validate.rs are extended with bound checks: transport/log_level use the mcp_ws helpers, manager_url is parsed via parse_manager_addr, ws_timeout_ms must be > 0.
…id / --corr-id / --mcp-log-level / --mcp-ws-timeout-ms Adds a shared McpClientWsArgs struct flattened into LaunchArgs and TestArgs. Values are validated at the CLI boundary (map_mcp_ws_args): transport must be ws|legacy|auto, log_level must be one of off|error|warn|info|debug|trace, ws_timeout_ms must be >= 1, manager_url must include host:port, client_uid/corr_id must not contain ';' (the /C payload is semicolon-delimited). Wired through transport-neutral McpClientWsRequest in use_cases::request, threaded into LaunchRequest and TestRequest so that downstream MCP service callers can also opt into the WS-mode without changes once they need it. The actual /C payload assembly happens in the next commit. Per-launch random client_uid is left to the use-case layer. By contract the kind is computed internally from the entry-point and is NOT exposed via CLI.
launch_app: - effective_launch_options now returns (LaunchOptions, Option<McpResolutionMeta>); meta drives the new LaunchResult fields (transport, client_uid, kind, manager_url, corr_id, mcp_port). - decide_mcp_transport probes manager_url with PROBE_TIMEOUT_MS and returns ws|legacy according to CLI/config preference; auto falls back to legacy when probe fails. - WS-mode emits 'mcpMode=ws;manager_url=...;client_uid=<UUID>;kind= v8_runner_client|vanessa_test_client;corr_id=vr-<uid8>; mcp_log_level=...;mcp_ws_timeout_ms=...'. - Legacy branch keeps the existing 'runMcp[=...][;mcpPort=...]' exactly as before for back-compat. run_tests: - After build_platform_launch the coordinator calls apply_test_mcp_ws_payload, which appends the WS snippet to the existing /C (RunUnitTests=... or VA player payload). Resolution errors are logged as warn and skipped, preserving prior behavior. - yaxunit_runner / vanessa_test_client kinds are picked from PreparedRun. LaunchResult: new optional fields are skip-if-none, so JSON envelopes for non-MCP launches are byte-identical to the previous shape.
- launch_app::tests::client_mcp_launch_does_not_prepare_configured_tool_extension:
pin transport to Legacy so the test stays deterministic in
environments where a session-manager listener happens to be live
on 127.0.0.1:4000 (auto would otherwise pick WS).
- tests/cli_launch.rs::launch_mcp_va_builds_payload_from_configured_port_and_ordinary_mode:
add --mcp-transport legacy and assert the new JSON fields
transport=legacy and mcp_port=9874 in the launch envelope.
- Regenerate docs/schemas/v8project.schema.json and
docs/schemas/v8project.local.schema.json to include the new
tools.client_mcp.{transport,manager_url,log_level,ws_timeout_ms}
fields (UPDATE_CONFIG_SCHEMAS=1 cargo test
generated_schema_artifacts_are_current).
tests/cli_launch.rs: 6 new integration tests covering the four behaviors required by the spec: - launch mcp --mcp-transport=legacy emits /C"runMcp;mcpPort=..." and a JSON envelope with transport=legacy + mcp_port. - launch mcp --mcp-transport=ws against a live ephemeral listener emits /C"mcpMode=ws;manager_url=...;client_uid=...;kind= v8_runner_client;corr_id=...;mcp_log_level=...;mcp_ws_timeout_ms= ..." plus matching JSON fields (transport=ws, client_uid, kind, manager_url, corr_id). - launch mcp --mcp-transport=ws against an unreachable port fails with 'session-manager unreachable' diagnostic. - launch mcp --mcp-transport=auto falls back to legacy when the manager is unreachable. - launch mcp --manager-url with bare host (no port) is rejected at argument-mapping time. - launch mcp --mcp-ws-timeout-ms 0 is rejected as zero. src/use_cases/run_tests/helpers.rs: 3 unit tests for append_mcp_ws_snippet covering existing /C, missing /C and empty /C. Real 1C runs are not invoked in any of these tests — the script in $tempdir/platform/bin/1cv8c just dumps args to a log.
- README: add a 'Подключение к session-manager (WS-режим)' subsection pointing at docs/CONFIGURATION.md and the v8-client-session-manager repo. - docs/CONFIGURATION.md: extend tools.client_mcp YAML example with the new transport/manager_url/log_level/ws_timeout_ms fields and add a 'WS-режим к session-manager' subsection that documents the internal kind mapping, the /C payload shape, the CLI flags and the auto-probe behavior. - src/use_cases/mcp_ws.rs: simplify — derive Default for McpClientTransport instead of a hand-written impl, drop unused validate_log_level/UnsupportedLogLevel pair (the boundary uses is_supported_log_level directly via map_mcp_ws_args), and switch the matching test over. - cargo fmt.
Дополняет агентный скил v8-runner новой секцией. Источник правды — docs/CONFIGURATION.md (`tools.client_mcp` + «WS-режим к session-manager»), здесь — оперативная справка для агента. Что добавлено: - v8-runner/references/project-workflows.md: новая секция «WS-режим к session-manager» — транспорт/auto-probe, /C payload, internal kind mapping (v8_runner_client / vanessa_test_client / yaxunit_runner), override-флаги, JSON-output, замечание что менеджер v8-runner не поднимает (отдельный шаг). - v8-runner/references/command-selection.md: после блока launch mcp добавлены примеры WS-флагов (--mcp-transport, --manager-url, --client-uid, --corr-id, --mcp-log-level) с указанием на полный раздел в project-workflows.md. - v8-runner/SKILL.md: в Default Use-Case Routing — буллет про WS-режим с краткой логикой auto-probe и фиксированным kind-mapping (без CLI override).
…init
Скил знал про команду config init, но не описывал, как агенту решить
какие флаги передать без лишних вопросов пользователю. Decision-tree
прятался в коде src/use_cases/config_init.rs (auto-detect format,
discover sources, choose builder).
Что добавлено:
- v8-runner/references/bootstrap.md — новый reference. Содержит:
- проверка существующего v8project.yaml (force-семантика);
- signals в файловой системе для format=designer|edt|auto;
- когда переключать builder с DESIGNER на IBCMD;
- три формы --connection (File auto-managed / File existing /
Srvr server-bound) с дефолтом File=build/ib;
- правила «когда задавать вопросы»: 4 ситуации и формулировки;
- примеры flow для типичных проектов (File-Designer, EDT, mixed,
server-bound);
- чек-лист what-to-inspect после config init.
- v8-runner/SKILL.md: новый bullet в decision entrypoint, ссылающийся
на bootstrap.md.
Источник правды по фактам — src/use_cases/config_init.rs (discover_sources,
choose_format, build_source_sets) + src/cli/args.rs (ConfigInitArgs).
- replace legacy transport config value with mcp\n- harden WS payload validation and schema boundaries\n- update docs, schemas, and launch tests
- clarify WS timeout documentation\n- include manager_url parse diagnostics\n- remove legacy wording from public docs
`/C"value"` was passed as a single argv element with literal `"` chars in the payload — `std::process::Command` bypasses the shell on both Linux (execve) and Windows (CreateProcess), so the platform received `/C"…"` as one unknown key and replied with «Неверные или отсутствующие параметры соединения с информационной базой». Splitting into `/C` and the payload as two argv tokens makes the platform parse `/C` as the command-line parameter key and the next token as its value. Tests adjusted to match the new format: argv pairs `["/C", "<value>"]` in unit tests and `/C\n<value>\n` in the integration args.log dump (printf '%s\n' "$@" puts each argv on its own line). Recovered from a dangling stash (cdb1e0a0 "fix/c-arg-quoting WIP") that had been authored locally but never committed; rebuilds lost the patch.
Plain enterprise launches now honor MCP WS flags by appending mcpMode=ws to /C without a kind field. Specialized launch mcp flows keep the existing kind-bearing payload. Tests: CC=/usr/bin/gcc cargo test --test cli_launch
Launch mcp va now mirrors the canonical Vanessa manager startup: /TESTMANAGER, unsafe-action protection disabled, /Execute vanessa-automation.epf, and VAParams without StartFeaturePlayer. WS mode publishes kind=vanessa_test_client and keeps the detached process alive in its own session.
WalkthroughPR adds WS transport support for MCP launch and test flows, extends config/CLI/request contracts, wires transport resolution into use cases, and updates launch argument handling plus detached Unix process startup behavior. ChangesMCP WebSocket Session-Manager Support
Launch argument and process behavior
Estimated code review effort🎯 4 (Complex) | ⏱️ ~60 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Обновил этот WS PR связанными follow-up fixes из fork:
Зачем это в этом PR: это не отдельная фича поверх WS, а доведение WS-режима до рабочего контура с Targeted checks in the update worktree:
|
Actionable comments posted: 7 Caution Some comments are outside the diff and can’t be posted inline due to platform limitations.
|
Actionable comments posted: 4 🤖 Prompt for all review comments with AI agents🪄 Autofix (Beta)Fix all unresolved CodeRabbit comments on this PR:
ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (20)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (7)
|
Actionable comments posted: 1 🤖 Prompt for all review comments with AI agents🪄 Autofix (Beta)Fix all unresolved CodeRabbit comments on this PR:
ℹ️ Review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
🚧 Files skipped from review as they are similar to previous changes (1)
|
Caution Some comments are outside the diff and can’t be posted inline due to platform limitations.
|
Относительная ссылка GitHub не умеет переходить за пределы репозитория по относительным путям в README — ссылка приведёт к 404. Если 🛠️ Предлагаемое исправление-1С-клиента к [`v8-client-session-manager`](../v8-client-session-manager/) вместо запуска
+1С-клиента к [`v8-client-session-manager`](https://github.com/<org>/v8-client-session-manager) вместо запуска🤖 Prompt for AI Agents✅ Addressed in commit 68acc8f |
Добавьте защиту от Сейчас на Line 852-858 проверяется только формат адреса, но не запрещается Тут лучше валидировать Предлагаемое изменение if let Some(url) = config.tools.client_mcp.manager_url.as_deref() {
+ if url.contains(';') {
+ return Err(ConfigValidationError::InvalidMcpClientManagerUrl(
+ url.to_owned(),
+ ));
+ }
if crate::use_cases::mcp_ws::parse_manager_addr(url).is_err() {
return Err(ConfigValidationError::InvalidMcpClientManagerUrl(
url.to_owned(),
));
}
}🤖 Prompt for AI Agents✅ Addressed in commit 68acc8f |
В
Предлагаю либо валидировать значения здесь же (regex-allowlist для каждого поля), либо добавить дешёвый guard: 🛡️ Минимальный guard на forbidden chars impl WsLaunchParams {
+ fn assert_no_separator(field: &str, value: &str) {
+ debug_assert!(
+ !value.contains(|c: char| c == ';' || c == '='),
+ "ws payload field '{field}' must not contain ';' or '=': {value:?}"
+ );
+ }
+
pub fn payload_snippet(&self) -> String {
+ Self::assert_no_separator("manager_url", &self.manager_url);
+ Self::assert_no_separator("client_uid", &self.client_uid);
+ Self::assert_no_separator("corr_id", &self.corr_id);
+ Self::assert_no_separator("log_level", &self.log_level);
format!(
"mcpMode=ws;manager_url={};client_uid={};kind={};corr_id={};mcp_log_level={};mcp_ws_timeout_ms={}",Чище — поднять валидацию на CLI/config-уровне и возвращать 🤖 Prompt for AI Agents✅ Addressed in commit 68acc8f |
Предлагаю либо паддить нулями до 8 символов, либо генерировать 🤖 Prompt for AI Agents✅ Addressed in commit 68acc8f |
🧩 Analysis chain🌐 Web query:
💡 Result: std::net::ToSocketAddrs performs blocking DNS resolution via the OS's getaddrinfo (or equivalent), with no configurable timeout in std; it relies on OS defaults (e.g., ~5s on Linux, 15s on Windows) [1][2][3]. The docs explicitly warn it "may block the current thread while resolution is performed" [1]. TcpStream::connect(A) where A: ToSocketAddrs first calls to_socket_addrs (blocking), then attempts connections sequentially without connect timeout [4]. TcpStream::connect_timeout requires a single &SocketAddr, so cannot directly use ToSocketAddrs [4]. Best practices to avoid indefinite blocking: 1. Use async runtimes: - Tokio: tokio::net::lookup_host(host_port).await? resolves non-blockingly (uses spawn_blocking internally) [5][6]. Then tokio::net::TcpStream::connect(addr).await? with timeout via tokio::time::timeout [6]. - async-std: similar async ToSocketAddrs [7]. 2. Synchronous with timeout: Spawn a thread for resolution, use std::thread::spawn and crossbeam_channel or similar with timeout [3][8]. Example: use std::net::{ToSocketAddrs, SocketAddr}; use std::time::Duration; use crossbeam_channel::{bounded, RecvTimeoutError}; fn resolve_with_timeout<T: ToSocketAddrs + Send + 'static>(addr: T, timeout: Duration) -> Result<Vec, Box> { let (tx, rx) = bounded(1); std::thread::spawn(move || { tx.send(addr.to_socket_addrs.unwrap.collect).unwrap; }); match rx.recv_timeout(timeout) { Ok(addrs) => Ok(addrs), Err(RecvTimeoutError::TimedOut) => Err("DNS timeout".into), _ => Err("channel error".into), } } [8][3] 3. Custom resolvers with timeouts: - hickory-resolver (formerly trust-dns-resolver): Tokio-based, configurable timeouts via ResolverBuilder [9]. Use resolver.lookup_ip(host)?.into_iter.map(|ip| SocketAddr::new(ip, port)) [9][10]. - hickory-to-socket-addrs crate: Direct ToSocketAddrs replacement using hickory-dns [10][11]. - c-ares-resolver: Configurable timeouts [12]. For production, prefer async (Tokio/async-std) or dedicated resolvers like hickory-resolver to avoid blocking and enable timeouts [10][3][6][9]. OS defaults prevent true indefinite hangs, but explicit control is best. Citations:
🏁 Script executed: # Find PROBE_TIMEOUT_MS definition
rg "PROBE_TIMEOUT_MS" --type rustRepository: alkoleft/v8-runner-rust Length of output: 239 🏁 Script executed: # Find all call sites of parse_manager_addr
rg "parse_manager_addr" --type rust -B 2 -A 2Repository: alkoleft/v8-runner-rust Length of output: 2877 🏁 Script executed: # Check the file context around parse_manager_addr
head -n 300 src/use_cases/mcp_ws.rs | tail -n 100Repository: alkoleft/v8-runner-rust Length of output: 3257 🏁 Script executed: # Look for async context and timeout usage in the file
rg "tokio::|timeout|async" src/use_cases/mcp_ws.rs -A 2 -B 2Repository: alkoleft/v8-runner-rust Length of output: 2806
Минимум — добавить в doc-комментарий предупреждение о блокировке DNS. Лучше — либо перейти на асинхронное разрешение ( 🤖 Prompt for AI Agents✅ Addressed in commit 68acc8f |
Не глотайте ошибку резолва транспорта для На Line 448-453 ошибка Сделайте 🤖 Prompt for AI Agents✅ Addressed in commit 68acc8f |
Неверный путь ключа в конфиге: На Line 48 указан несуществующий ключ. Это вводит в заблуждение при bootstrap и приводит к невалидному 🤖 Prompt for AI Agents✅ Addressed in commit 68acc8f |
Уточните описание Текст говорит, что это таймаут только для 🤖 Prompt for AI Agents✅ Addressed in commit cbaf405 |
Сделайте ошибку Сейчас для разных причин возвращается одно и то же сообщение 💡 Предлагаемый патч- if crate::use_cases::mcp_ws::parse_manager_addr(url).is_err() {
+ if let Err(err) = crate::use_cases::mcp_ws::parse_manager_addr(url) {
return Err(UseCaseError::new(
UseCaseErrorKind::Validation,
- format!("--manager-url must include host:port (got: {url})"),
+ format!("--manager-url is invalid: {err}"),
));
}📝 Committable suggestion
🤖 Prompt for AI Agents✅ Addressed in commit cbaf405 |
Тесты закрепляют потенциально неверный CLI-контракт ( Здесь и далее новые тесты утверждают 🤖 Prompt for AI Agents |
Синхронизируйте публичный контракт В этих строках фиксируется значение 🤖 Prompt for AI Agents |
Исправьте непарную кавычку. В строке 📝 Предлагаемое исправление-`launch mcp` передаёт `port` как `mcpPort` внутри `/C"runMcp..."`
+`launch mcp` передаёт `port` как `mcpPort` внутри `/C"runMcp..."`🧰 Tools🪛 LanguageTool[typographical] ~460-~460: Непарный символ: «"» скорей всего пропущен (RU_UNPAIRED_BRACKETS) 🤖 Prompt for AI Agents |
Summary
Добавляет WS-режим для клиентского MCP: 1С-клиент может подключаться к
v8-client-session-managerпо WebSocket, а приtransport: autoбез доступного менеджера v8-runner использует локальный HTTP MCP (runMcp).После review исправлено имя публичного режима: локальный MCP-транспорт называется
mcp, неlegacy.What Changed
ws | mcp | auto.--mcp-transport=mcpфорсирует локальный HTTP MCP без probe.--mcp-transport=autoделает короткий TCP-probemanager_url: доступен manager ->ws, иначе ->mcp.--json-messageдляlaunch mcpвозвращает типизированныйtransport: "ws" | "mcp".tools.client_mcp.transportв JSON Schema ограничен enum-омws | mcp | auto;legacyтеперь отклоняется на schema/runtime boundary./Cpayload hardened: значения кодируются для защиты от;/=format injection; CLI/config дополнительно валидируют опасные значения.manager_urlвалидируется как IP:port, чтобы auto-probe не зависал на блокирующем DNS lookup.test yaxunit/test vaбольше не глотают ошибку explicit WS resolution, а возвращают structured setup failure.README,docs/CONFIGURATION.md, schemas и repo-local skillv8-runner/SKILL.md.Config
portподtools.client_mcpсохраняется для локального MCP (runMcp) режима.Review Fixes Included
v8-client-session-manageris absolute.v8-runner/references/bootstrap.md:tools.connection->infobase.connection.ws_timeout_msschema minimum is1.transport=legacyreplaced withtransport=mcpin CLI/config/docs/tests.default_corr_idpads short client ids to keepvr-<8 chars>shape.log_levelvalidation is case-insensitive and normalized for payload output.Test Plan
CC=/usr/bin/gcc UPDATE_CONFIG_SCHEMAS=1 ~/.cargo/bin/cargo test generated_schema_artifacts_are_currentCC=/usr/bin/gcc ~/.cargo/bin/cargo test schemas_and_loader_reject_invalid_client_mcp_transportCC=/usr/bin/gcc ~/.cargo/bin/cargo test mcp_wsCC=/usr/bin/gcc ~/.cargo/bin/cargo test --test cli_launchFull
cargo testwas also run locally: 684 passed, 2 environment-related failures unrelated to this PR surface (/usr/local/bin/1cedtcliautodiscovery in a not-found test, and one process kill liveness check). Existing warning remains:src/use_cases/tool_extension.rs:126unused variable.Summary by CodeRabbit
transport=auto/ws/mcpс настройкамиmanager_url,client_uid,corr_id,log_level,ws_timeout_ms, включая автопроверку и fallback на legacy MCP.v8project.yamlдляclient_mcp(транспортные параметры, ограничения и валидация)./Cи проверок параметров.