diff --git a/SKILL/SKILL.md b/SKILL/SKILL.md index 2b0e4c5..5359fbc 100644 --- a/SKILL/SKILL.md +++ b/SKILL/SKILL.md @@ -83,7 +83,7 @@ v8-runner init - Extension properties need synchronization: use `v8-runner extensions` or `extensions --name `. - Infobase changes need to become Git-visible files: check `git status`, then run the relevant `v8-runner dump ...` command. - Source files need conversion between Designer and EDT: use `v8-runner convert`; this is CLI-only and does not use the infobase. -- Existing `.cf` or `.cfe` artifacts need to be applied to an infobase: use `v8-runner load ...`. +- Existing `.cf` or `.cfe` artifacts need to be applied to an infobase: use `v8-runner load ...`. To create a missing extension, only Designer artifact loading is supported: `v8-runner load --path .cfe --mode load --extension `; it does not create schema/MCP objects or build extension sources. - Release artifacts need to be exported or external artifacts published: use `v8-runner make ...` or the `artifacts` alias. - Need a 1C UI session: use `v8-runner launch designer`, `launch thin`, `launch thick`, or `launch ordinary`. - Need an observable local external EPF runtime gate: use `launch thin --execute --output --stderr-output --wait-for-exit --wait-timeout-ms `. This opt-in mode is limited to explicit `.epf` files, reports PID/exit-or-timeout/artifacts, treats timeout as a CLI failure after terminating the client group, and rejects raw or configured `/C`, `/Execute`, and `/Out` aliases; callers must inspect the reported exit code because non-zero EPF exit is observational rather than a CLI failure; plain launch remains asynchronous. diff --git a/docs/CAPABILITIES.md b/docs/CAPABILITIES.md index 6483c06..fbd9e7c 100644 --- a/docs/CAPABILITIES.md +++ b/docs/CAPABILITIES.md @@ -279,6 +279,7 @@ v8-runner load --path [--mode ] [--settings ] [--extens - Поддерживает `.cf` и `.cfe`. - Работает только для `format=DESIGNER` и `builder=DESIGNER`. - `.cfe` требует `--extension`. +- Если probe сообщает, что расширение отсутствует, `load --path .cfe --mode load --extension ` создаёт его только из Designer-артефакта: выполняет `/LoadCfg` и затем `/UpdateDBCfg` с `-Extension `. Команда не создаёт schema/MCP-объекты и не запускает build исходников. - `--mode merge` требует `--settings `. - `load --mode update` не поддержан; используйте `load` или `merge`. diff --git a/tests/cli_load.rs b/tests/cli_load.rs index 2fafb3e..07bcf4b 100644 --- a/tests/cli_load.rs +++ b/tests/cli_load.rs @@ -193,6 +193,76 @@ fn merge_cfe_json_success_requires_extension_and_settings() { assert!(calls.contains("/UpdateDBCfg -Extension ExistingExt")); } +#[test] +fn load_cfe_json_creates_missing_extension_from_artifact() { + let (_dir, config_path, _binary_path, base_path, calls_log) = setup_project(); + fs::write(base_path.join("release.cfe"), "cfe").expect("artifact"); + + let output = v8_runner_command() + .args([ + "--config", + &config_path.display().to_string(), + "--json-message", + "load", + "--path", + "release.cfe", + "--mode", + "load", + "--extension", + "NewExt", + ]) + .output() + .expect("run command"); + + assert!(output.status.success()); + let payload: Value = serde_json::from_slice(&output.stdout).expect("json"); + assert_eq!(payload["ok"], true); + assert_eq!(payload["command"], "load"); + assert_eq!(payload["data"]["mode"], "load"); + assert_eq!(payload["data"]["artifact_type"], "extension_cfe"); + assert_eq!(payload["data"]["extension"], "NewExt"); + assert_eq!( + payload["data"]["execution"]["payload"]["target_kind"], + "extension" + ); + assert_eq!( + payload["data"]["execution"]["payload"]["compatibility_state"], + "not_supported" + ); + assert_eq!(payload["data"]["execution"]["payload"]["applied"], true); + assert_eq!( + payload["data"]["execution"]["payload"]["update_db_cfg_ran"], + true + ); + + let calls = fs::read_to_string(calls_log).expect("calls"); + let calls = calls.lines().collect::>(); + let probe = calls + .iter() + .position(|call| { + call.contains("/CompareCfg") + && call.contains("ExtensionConfiguration") + && call.contains("ExtensionDBConfiguration") + && call.contains("-FirstName NewExt") + && call.contains("-SecondName NewExt") + }) + .expect("extension compatibility probe"); + let load = calls + .iter() + .position(|call| { + call.contains("/LoadCfg") && call.contains("release.cfe -Extension NewExt") + }) + .expect("load call with artifact and extension"); + let update = calls + .iter() + .position(|call| call.contains("/UpdateDBCfg -Extension NewExt")) + .expect("update call"); + assert!( + probe < load && load < update, + "extension probe must precede load, which must precede database update" + ); +} + #[test] fn load_update_mode_returns_validation_payload() { let (_dir, config_path, _binary_path, base_path, _calls_log) = setup_project();