From a8ae89119df8fad379eb92770f800a14113b473c Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Wed, 28 Oct 2026 01:47:11 +0900 Subject: [PATCH 01/30] protocol and backend: schemas held against mcpp's real output, the command table, mcppls's handshake, targets and platforms - protocol/protocol.schema.json: the backend's methods and notifications; the tests require the registered ones to be exactly these, and check a session's answers and notifications over the mock mcpp against them. - protocol/mcpp-contract.schema.json: the part of mcpp's control contract the backend reads; every golden fixture is checked against the definition protocol/fixtures.json names (src/schema.cppm: the JSON Schema subset used). - Fixtures recaptured from mcpp 2026.10.26.2 by `mcpp-ide-dev capture` (C++, replacing tools/capture-fixtures.sh); test-list.ndjson added. - spec/commands.json: the command table both editors declare and run; the backend serves it (`commands/list`, `menu/quick`) in the session's language. - `languageService/status`: which mcppls answers and whether it reads mcpp's result record (0.0.18); an older or missing one is reported with what to do. - `targets/list`: one row per target with its toolchains and the platform mcpp names for it; `project/summary` carries the platforms of the last plan. - A job's stream becomes job/plan, job/progress, job/diagnostic, job/artifact, test/result and test/summary; job/finished carries the envelope's diagnostics and artifacts. - `test/list` (mcpp test --list), `project/new`, `pack/start`; `--target` from the request or `mcpp.build.target`; a program that runs through a runner is debugged as the runner, its symbols read through the GDB JIT interface. - `mcpp-ide-dev gen vscode|jetbrains` writes the editors' declarations from spec/; `mcpp-ide-dev check-i18n` requires a Chinese entry for every string. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- build.mcpp | 10 +- mcpp.toml | 5 + protocol/fixtures.json | 22 + protocol/fixtures/build-database.json | 18 +- protocol/fixtures/build-failed.ndjson | 4 +- protocol/fixtures/build-manifest-error.ndjson | 2 +- protocol/fixtures/build-ok.ndjson | 6 +- protocol/fixtures/cache-list.json | 450 ++++++++-------- protocol/fixtures/index-list.json | 2 +- protocol/fixtures/launch.json | 6 +- protocol/fixtures/pack-formats.json | 2 +- protocol/fixtures/protocol-version.json | 2 +- protocol/fixtures/result-ok.json | 18 +- protocol/fixtures/search.json | 86 +-- protocol/fixtures/self-env.json | 6 +- protocol/fixtures/test-list.ndjson | 2 + protocol/fixtures/test.ndjson | 4 +- protocol/fixtures/toolchain-list.json | 18 +- protocol/fixtures/version.txt | 2 +- protocol/mcpp-contract.schema.json | 372 +++++++++++++ protocol/protocol.schema.json | 352 +++++++++++++ spec/commands.json | 100 ++++ spec/i18n/manifest.en.json | 36 +- spec/i18n/manifest.zh-cn.json | 36 +- spec/i18n/runtime.zh-cn.json | 357 +++++++------ spec/settings.json | 25 +- src/bin/dev.cpp | 496 ++++++++++++++++++ src/bin/mockmcpp.cpp | 20 +- src/languageservice.cppm | 134 +++++ src/mcpp.cppm | 30 ++ src/schema.cppm | 110 ++++ src/server.cppm | 475 +++++++++++++++-- src/spec.cppm | 29 + src/views.cppm | 116 ++++ tests/test_languageservice.cpp | 25 + tests/test_protocol.cpp | 160 ++++++ tests/test_views.cpp | 43 ++ tools/capture-fixtures.sh | 58 -- 38 files changed, 3052 insertions(+), 587 deletions(-) create mode 100644 protocol/fixtures.json create mode 100644 protocol/fixtures/test-list.ndjson create mode 100644 protocol/mcpp-contract.schema.json create mode 100644 protocol/protocol.schema.json create mode 100644 spec/commands.json create mode 100644 src/bin/dev.cpp create mode 100644 src/languageservice.cppm create mode 100644 src/schema.cppm create mode 100644 tests/test_languageservice.cpp create mode 100644 tests/test_protocol.cpp delete mode 100755 tools/capture-fixtures.sh diff --git a/build.mcpp b/build.mcpp index 1d833a5..8c6cebd 100644 --- a/build.mcpp +++ b/build.mcpp @@ -1,11 +1,12 @@ // mcpp-ide's build program: the backend's view of spec/, generated where the build writes. // // spec/ is the one source of every editor-facing declaration (settings, presets, runtime strings, -// mcpp's manifest keys and build-program directives). The backend reads it as JSON at startup, so +// mcpp's manifest keys and build-program directives, the command table and the editors' strings). +// The backend reads it as JSON at startup, so // this program only carries the files into a module, `mcppide.generated.spec`, as string literals: // nothing is generated into the repository and nothing parses JSON here. The editors' declarations // (package.json's contributes, plugin.xml's actions, the message bundles) are written by -// `mcpp-ide-gen`, a program of this package, when an adapter is built. +// `mcpp-ide-dev gen`, a program of this package, when an adapter is built. import std; import mcpp; @@ -44,10 +45,13 @@ int main() { const std::filesystem::path root = env_or_empty("MCPP_MANIFEST_DIR"); const std::filesystem::path out = env_or_empty("MCPP_OUT_DIR"); const std::filesystem::path spec = root / "spec"; - const std::array, 5> files{{ + const std::array, 8> files{{ {"kSettingsJson", "settings.json"}, {"kPresetsJson", "presets.json"}, + {"kCommandsJson", "commands.json"}, {"kRuntimeZhCnJson", "i18n/runtime.zh-cn.json"}, + {"kManifestEnJson", "i18n/manifest.en.json"}, + {"kManifestZhCnJson", "i18n/manifest.zh-cn.json"}, {"kTomlSchemaJson", "toml-schema.json"}, {"kBuildScriptApiJson", "buildscript-api.json"}, }}; diff --git a/mcpp.toml b/mcpp.toml index f720a83..0cd809b 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -35,6 +35,11 @@ main = "src/main.cpp" kind = "bin" main = "src/bin/mockmcpp.cpp" +# The repository's tools: fixture capture, the editors' declarations from spec/, the i18n check. +[targets.mcpp-ide-dev] +kind = "bin" +main = "src/bin/dev.cpp" + [dependencies] os = "0.2.0" diff --git a/protocol/fixtures.json b/protocol/fixtures.json new file mode 100644 index 0000000..6b05bed --- /dev/null +++ b/protocol/fixtures.json @@ -0,0 +1,22 @@ +{ + "description": "Which definition of mcpp-contract.schema.json each golden fixture is checked against. `lines`: every line of an NDJSON file against `each`; otherwise the whole document against `schema`. `version.txt` is mcpp's own `--version` line.", + "fixtures": [ + { "file": "protocol-version.json", "schema": "protocolVersion" }, + { "file": "build-ok.ndjson", "each": "buildStreamLine" }, + { "file": "build-failed.ndjson", "each": "buildStreamLine" }, + { "file": "build-manifest-error.ndjson", "each": "buildStreamLine" }, + { "file": "result-ok.json", "schema": "resultRecord" }, + { "file": "launch.json", "schema": "launchEnvelope" }, + { "file": "test.ndjson", "each": "testStreamLine" }, + { "file": "test-list.ndjson", "each": "testListLine" }, + { "file": "build-database.json", "schema": "buildDatabaseEnvelope" }, + { "file": "toolchain-list.json", "schema": "toolchainListEnvelope" }, + { "file": "search.json", "schema": "searchEnvelope" }, + { "file": "cache-list.json", "schema": "cacheListEnvelope" }, + { "file": "index-list.json", "schema": "indexListEnvelope" }, + { "file": "pack-formats.json", "schema": "packFormatsEnvelope" }, + { "file": "self-env.json", "schema": "selfEnvEnvelope" }, + { "file": "build-platform.ndjson", "each": "buildStreamLine", "optional": true }, + { "file": "toolchain-list-platform.json", "schema": "toolchainListEnvelope", "optional": true } + ] +} diff --git a/protocol/fixtures/build-database.json b/protocol/fixtures/build-database.json index 12c45fa..3b7b488 100644 --- a/protocol/fixtures/build-database.json +++ b/protocol/fixtures/build-database.json @@ -4,7 +4,7 @@ "ide": { "generator": { "name": "mcpp", - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "profile-version": "0.3.0", "toolchains": { @@ -60,20 +60,20 @@ "-c", "@ROOT@/src/main.cpp", "-o", - "@HOME@/.mcpp/cache/build-database/d0ed76fa8386e035/target/x86_64-linux-gnu/b95fa85150d74e3d/obj/main.o" + "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30/obj/main.o" ], "ide": { "role": "non-module" }, "local-arguments": [], - "object": "@HOME@/.mcpp/cache/build-database/d0ed76fa8386e035/target/x86_64-linux-gnu/b95fa85150d74e3d/obj/main.o", + "object": "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30/obj/main.o", "private": false, "provides": {}, "requires": [ "std" ], "source": "@ROOT@/src/main.cpp", - "work-directory": "@HOME@/.mcpp/cache/build-database/d0ed76fa8386e035/target/x86_64-linux-gnu/b95fa85150d74e3d" + "work-directory": "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30" } ], "visible-sets": [ @@ -114,20 +114,20 @@ "-c", "@ROOT@/tests/test_smoke.cpp", "-o", - "@HOME@/.mcpp/cache/build-database/d0ed76fa8386e035/target/x86_64-linux-gnu/b95fa85150d74e3d/obj/test_smoke.o" + "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30/obj/test_smoke.o" ], "ide": { "role": "non-module" }, "local-arguments": [], - "object": "@HOME@/.mcpp/cache/build-database/d0ed76fa8386e035/target/x86_64-linux-gnu/b95fa85150d74e3d/obj/test_smoke.o", + "object": "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30/obj/test_smoke.o", "private": false, "provides": {}, "requires": [ "std" ], "source": "@ROOT@/tests/test_smoke.cpp", - "work-directory": "@HOME@/.mcpp/cache/build-database/d0ed76fa8386e035/target/x86_64-linux-gnu/b95fa85150d74e3d" + "work-directory": "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30" } ], "visible-sets": [ @@ -186,7 +186,7 @@ ], "version": 1 }, - "inputs-fingerprint": "fnv1a:a7fbe48a39924203", + "inputs-fingerprint": "fnv1a:3c9c1199d9bc1143", "spec": { "name": "s1", "version": "0.3.0" @@ -217,7 +217,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/build-failed.ndjson b/protocol/fixtures/build-failed.ndjson index 5ab3ada..d2ca619 100644 --- a/protocol/fixtures/build-failed.ndjson +++ b/protocol/fixtures/build-failed.ndjson @@ -1,6 +1,6 @@ -{"configuration":{"fingerprint":"b95fa85150d74e3d","outputDir":"@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d","profile":"dev","triple":"x86_64-linux-gnu"},"event":"plan","kind":"mcpp.event","schemaVersion":1} +{"configuration":{"fingerprint":"b4dbdb186bc3ef30","outputDir":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30","profile":"dev","triple":"x86_64-linux-gnu"},"event":"plan","kind":"mcpp.event","schemaVersion":1} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":2} {"diagnostic":{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"},"event":"diagnostic","kind":"mcpp.event","schemaVersion":1} -{"data":{"artifacts":[],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/compile_commands.json","configuration":{"fingerprint":"b95fa85150d74e3d","outputDir":"@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d","profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"}],"finishedAt":1792988800526,"pid":1110693,"startedAt":1792988800464,"status":"failed"},"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"build failed in app v0.1.0 (.)","severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.1"},"schemaVersion":1} +{"data":{"artifacts":[],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/compile_commands.json","configuration":{"fingerprint":"b4dbdb186bc3ef30","outputDir":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30","profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"}],"finishedAt":1793118345609,"pid":1768262,"startedAt":1793118345588,"status":"failed"},"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"build failed in app v0.1.0 (.)","severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.2"},"schemaVersion":1} diff --git a/protocol/fixtures/build-manifest-error.ndjson b/protocol/fixtures/build-manifest-error.ndjson index b1bff8c..42b0386 100644 --- a/protocol/fixtures/build-manifest-error.ndjson +++ b/protocol/fixtures/build-manifest-error.ndjson @@ -1 +1 @@ -{"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"@ROOT@/mcpp.toml:1:9: error: expected ']'","path":"@ROOT@/mcpp.toml","range":{"end":{"column":9,"line":1},"start":{"column":9,"line":1}},"severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.1"},"schemaVersion":1} +{"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"@ROOT@/mcpp.toml:1:9: error: expected ']'","path":"@ROOT@/mcpp.toml","range":{"end":{"column":9,"line":1},"start":{"column":9,"line":1}},"severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.2"},"schemaVersion":1} diff --git a/protocol/fixtures/build-ok.ndjson b/protocol/fixtures/build-ok.ndjson index 2742643..8aafe41 100644 --- a/protocol/fixtures/build-ok.ndjson +++ b/protocol/fixtures/build-ok.ndjson @@ -1,9 +1,9 @@ -{"configuration":{"fingerprint":"b95fa85150d74e3d","outputDir":"@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d","profile":"dev","triple":"x86_64-linux-gnu"},"event":"plan","kind":"mcpp.event","schemaVersion":1} +{"configuration":{"fingerprint":"b4dbdb186bc3ef30","outputDir":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30","profile":"dev","triple":"x86_64-linux-gnu"},"event":"plan","kind":"mcpp.event","schemaVersion":1} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":4} {"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":4} {"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":4} {"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":4} -{"artifact":{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/bin/app"},"event":"artifact","kind":"mcpp.event","schemaVersion":1} -{"data":{"artifacts":[{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/bin/app"}],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/compile_commands.json","configuration":{"fingerprint":"b95fa85150d74e3d","outputDir":"@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d","profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[],"finishedAt":1792988794753,"pid":1110202,"startedAt":1792988793983,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.1"},"schemaVersion":1} +{"artifact":{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app"},"event":"artifact","kind":"mcpp.event","schemaVersion":1} +{"data":{"artifacts":[{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app"}],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/compile_commands.json","configuration":{"fingerprint":"b4dbdb186bc3ef30","outputDir":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30","profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[],"finishedAt":1793118343698,"pid":1767942,"startedAt":1793118343022,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.2"},"schemaVersion":1} diff --git a/protocol/fixtures/cache-list.json b/protocol/fixtures/cache-list.json index 6467610..354f857 100644 --- a/protocol/fixtures/cache-list.json +++ b/protocol/fixtures/cache-list.json @@ -2,367 +2,367 @@ "data": { "entries": [ { - "accessed": 1791677267, - "bytes": 2776, + "accessed": 1793071043, + "bytes": 2808, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/52308de74c39d7c3", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/26916f34b8cd3aed", "files": 3, - "key": "52308de74c39d7c3", + "key": "26916f34b8cd3aed", "kind": "pkg", "label": "local-dev/local-dev.gfx-runtime@1.0.0" }, { - "accessed": 1791677267, - "bytes": 2792, + "accessed": 1793071043, + "bytes": 4688, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/1fbe65e5d3605e2d", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/27e4d0283d6e95aa", "files": 3, - "key": "1fbe65e5d3605e2d", + "key": "27e4d0283d6e95aa", "kind": "pkg", "label": "local-dev/local-dev.gfx-runtime@1.0.0" }, { - "accessed": 1792709160, - "bytes": 4680, + "accessed": 1793071043, + "bytes": 2792, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/d48887d890ed2e56", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/07829ab3ec4688f8", "files": 3, - "key": "d48887d890ed2e56", + "key": "07829ab3ec4688f8", "kind": "pkg", "label": "local-dev/local-dev.gfx-runtime@1.0.0" }, { - "accessed": 1791677267, - "bytes": 4680, + "accessed": 1793032871, + "bytes": 4161448, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/06f9fca16eaa839c", - "files": 3, - "key": "06f9fca16eaa839c", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/ac258dcd248798bf", + "files": 109, + "key": "ac258dcd248798bf", "kind": "pkg", - "label": "local-dev/local-dev.gfx-runtime@1.0.0" + "label": "compat/compat.mbedtls@3.6.1" }, { - "accessed": 1792709162, - "bytes": 2776, + "accessed": 1793030032, + "bytes": 4161448, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/a32b8d4598f8ebf4", - "files": 3, - "key": "a32b8d4598f8ebf4", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/2b62ed5aedbb0c90", + "files": 109, + "key": "2b62ed5aedbb0c90", "kind": "pkg", - "label": "local-dev/local-dev.gfx-runtime@1.0.0" + "label": "compat/compat.mbedtls@3.6.1" }, { - "accessed": 1792709161, - "bytes": 2792, + "accessed": 1793118305, + "bytes": 4165216, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/d24791002658750b", - "files": 3, - "key": "d24791002658750b", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/c4f67483e585bf28", + "files": 109, + "key": "c4f67483e585bf28", "kind": "pkg", - "label": "local-dev/local-dev.gfx-runtime@1.0.0" + "label": "compat/compat.mbedtls@3.6.1" }, { - "accessed": 1792967289, - "bytes": 176728, + "accessed": 1793064906, + "bytes": 1248, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/mcpplibs.capi/mcpplibs.capi.lua@0.0.3/0f183c5b84a9b8ac", - "files": 4, - "key": "0f183c5b84a9b8ac", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/4bd055d3e639f838", + "files": 2, + "key": "4bd055d3e639f838", "kind": "pkg", - "label": "mcpplibs.capi/mcpplibs.capi.lua@0.0.3" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792203602, - "bytes": 176480, + "accessed": 1793045336, + "bytes": 2960, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/mcpplibs.capi/mcpplibs.capi.lua@0.0.3/6016ba4d29bffdeb", - "files": 4, - "key": "6016ba4d29bffdeb", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/1212e78f9ca6f89b", + "files": 2, + "key": "1212e78f9ca6f89b", "kind": "pkg", - "label": "mcpplibs.capi/mcpplibs.capi.lua@0.0.3" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792370874, - "bytes": 176248, + "accessed": 1793045090, + "bytes": 1248, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/mcpplibs.capi/mcpplibs.capi.lua@0.0.3/b378cca6a6d45341", - "files": 4, - "key": "b378cca6a6d45341", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/0dd55b9dcbefef55", + "files": 2, + "key": "0dd55b9dcbefef55", "kind": "pkg", - "label": "mcpplibs.capi/mcpplibs.capi.lua@0.0.3" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792206406, - "bytes": 176552, + "accessed": 1793116930, + "bytes": 3256, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/mcpplibs.capi/mcpplibs.capi.lua@0.0.3/2cd4f2f2a0be0c0e", - "files": 4, - "key": "2cd4f2f2a0be0c0e", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/8162763afcdefca8", + "files": 2, + "key": "8162763afcdefca8", "kind": "pkg", - "label": "mcpplibs.capi/mcpplibs.capi.lua@0.0.3" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792364093, - "bytes": 176480, + "accessed": 1793031941, + "bytes": 2952, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/mcpplibs.capi/mcpplibs.capi.lua@0.0.3/344bd49a9bf94516", - "files": 4, - "key": "344bd49a9bf94516", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/b9cc3b9317e9ff85", + "files": 2, + "key": "b9cc3b9317e9ff85", "kind": "pkg", - "label": "mcpplibs.capi/mcpplibs.capi.lua@0.0.3" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792952901, - "bytes": 134736, + "accessed": 1793053112, + "bytes": 2936, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/mcpplibs.capi/mcpplibs.capi.lua@0.0.3/95ffb586015a07a1", - "files": 4, - "key": "95ffb586015a07a1", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/329610f00b3d2509", + "files": 2, + "key": "329610f00b3d2509", "kind": "pkg", - "label": "mcpplibs.capi/mcpplibs.capi.lua@0.0.3" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792713472, - "bytes": 176552, + "accessed": 1793115868, + "bytes": 3280, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/mcpplibs.capi/mcpplibs.capi.lua@0.0.3/6f7b89c6cd9fb6e8", - "files": 4, - "key": "6f7b89c6cd9fb6e8", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/fd9e8ec519362697", + "files": 2, + "key": "fd9e8ec519362697", "kind": "pkg", - "label": "mcpplibs.capi/mcpplibs.capi.lua@0.0.3" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792823210, - "bytes": 134560, + "accessed": 1793045442, + "bytes": 2952, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/mcpplibs.capi/mcpplibs.capi.lua@0.0.3/54495e738950708b", - "files": 4, - "key": "54495e738950708b", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/dc0c93e76254d2a5", + "files": 2, + "key": "dc0c93e76254d2a5", "kind": "pkg", - "label": "mcpplibs.capi/mcpplibs.capi.lua@0.0.3" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1791652822, - "bytes": 941448, + "accessed": 1793033974, + "bytes": 2968, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libserial@1.0.0/c092aaf40bc0d0f3", - "files": 4, - "key": "c092aaf40bc0d0f3", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/aab54974d9d305e9", + "files": 2, + "key": "aab54974d9d305e9", "kind": "pkg", - "label": "compat/compat.libserial@1.0.0" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1791652810, - "bytes": 871648, + "accessed": 1793074379, + "bytes": 2960, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libserial@1.0.0/8e4a357574f780cc", - "files": 4, - "key": "8e4a357574f780cc", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/5af9be881da9ccc8", + "files": 2, + "key": "5af9be881da9ccc8", "kind": "pkg", - "label": "compat/compat.libserial@1.0.0" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1791652813, - "bytes": 968808, + "accessed": 1793064836, + "bytes": 1248, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libserial@1.0.0/4c916f37baee7b57", - "files": 4, - "key": "4c916f37baee7b57", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/f9c3d1a8a7876dbe", + "files": 2, + "key": "f9c3d1a8a7876dbe", "kind": "pkg", - "label": "compat/compat.libserial@1.0.0" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1791529337, - "bytes": 4166648, + "accessed": 1793043363, + "bytes": 1248, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/b992eedd40df7235", - "files": 109, - "key": "b992eedd40df7235", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/aa1597a4809bded3", + "files": 2, + "key": "aa1597a4809bded3", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792825872, - "bytes": 1701064, + "accessed": 1793031127, + "bytes": 3232, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/7a499588c05602ff", - "files": 109, - "key": "7a499588c05602ff", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/975707438b5b5b4a", + "files": 2, + "key": "975707438b5b5b4a", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792797319, - "bytes": 4166648, + "accessed": 1793031200, + "bytes": 2952, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/ec8f0c0c818c1877", - "files": 109, - "key": "ec8f0c0c818c1877", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/bb6a79adc3f59398", + "files": 2, + "key": "bb6a79adc3f59398", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792203602, - "bytes": 3334696, + "accessed": 1793118326, + "bytes": 2952, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/af348fad86c20ca0", - "files": 109, - "key": "af348fad86c20ca0", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/57a40b9605feaaee", + "files": 2, + "key": "57a40b9605feaaee", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792955949, - "bytes": 1700280, + "accessed": 1793111430, + "bytes": 3216, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/c2145145e3312941", - "files": 109, - "key": "c2145145e3312941", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/22b7542e5cadbce7", + "files": 2, + "key": "22b7542e5cadbce7", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1791713236, - "bytes": 4164464, + "accessed": 1793117862, + "bytes": 2960, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/e2db66a4d6645126", - "files": 109, - "key": "e2db66a4d6645126", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/403a28faa71cca77", + "files": 2, + "key": "403a28faa71cca77", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792206407, - "bytes": 3354600, + "accessed": 1793115843, + "bytes": 3232, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/e7829f88da66a5e5", - "files": 109, - "key": "e7829f88da66a5e5", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/17e2feb6e3f0147c", + "files": 2, + "key": "17e2feb6e3f0147c", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792713472, - "bytes": 3354592, + "accessed": 1793033076, + "bytes": 2952, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/0d85eed6711d4b3e", - "files": 109, - "key": "0d85eed6711d4b3e", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/e0ede14d540cc89c", + "files": 2, + "key": "e0ede14d540cc89c", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792507440, - "bytes": 3328144, + "accessed": 1793045143, + "bytes": 3232, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/70d296ba1fe47eb8", - "files": 109, - "key": "70d296ba1fe47eb8", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/c0da81c79980dd9f", + "files": 2, + "key": "c0da81c79980dd9f", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792952901, - "bytes": 1620224, + "accessed": 1793118278, + "bytes": 2952, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/243be0c582e9398d", - "files": 109, - "key": "243be0c582e9398d", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/bd610edac4ea7d69", + "files": 2, + "key": "bd610edac4ea7d69", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792967289, - "bytes": 3360312, + "accessed": 1793033587, + "bytes": 2952, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/7c3fc89236ba2d26", - "files": 109, - "key": "7c3fc89236ba2d26", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/b42a151c1ec3d74f", + "files": 2, + "key": "b42a151c1ec3d74f", "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" + "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1792961878, - "bytes": 237368, + "accessed": 1793043269, + "bytes": 641776, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libdrm@2.4.134/b13fec4e2f736869", - "files": 6, - "key": "b13fec4e2f736869", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/ba17d9e31fb7f3e5", + "files": 12, + "key": "ba17d9e31fb7f3e5", "kind": "pkg", - "label": "compat/compat.libdrm@2.4.134" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792650269, - "bytes": 125968, + "accessed": 1793118326, + "bytes": 558088, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libdrm@2.4.134/e9484e08dab97ea6", - "files": 6, - "key": "e9484e08dab97ea6", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/c1bb7e4064dba71b", + "files": 12, + "key": "c1bb7e4064dba71b", "kind": "pkg", - "label": "compat/compat.libdrm@2.4.134" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792204194, - "bytes": 2960, + "accessed": 1793117862, + "bytes": 558136, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/e8737726367c2ff6", - "files": 2, - "key": "e8737726367c2ff6", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/6d496360aad37545", + "files": 12, + "key": "6d496360aad37545", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792274406, - "bytes": 1248, + "accessed": 1793033587, + "bytes": 558088, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/f7bee736510e746c", - "files": 2, - "key": "f7bee736510e746c", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/58f4b5f38eefa669", + "files": 12, + "key": "58f4b5f38eefa669", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792955949, - "bytes": 1248, + "accessed": 1793045153, + "bytes": 641776, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/00e2ed4d09944868", - "files": 2, - "key": "00e2ed4d09944868", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/68df645b652e834a", + "files": 12, + "key": "68df645b652e834a", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792967289, - "bytes": 2960, + "accessed": 1793074379, + "bytes": 558160, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/403a28faa71cca77", - "files": 2, - "key": "403a28faa71cca77", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/e6d6a48daf30b262", + "files": 12, + "key": "e6d6a48daf30b262", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792955949, - "bytes": 211056, + "accessed": 1793031200, + "bytes": 558088, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/799a680d2be2dd22", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/64da9b2a564c56ce", "files": 12, - "key": "799a680d2be2dd22", + "key": "64da9b2a564c56ce", "kind": "pkg", "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792204194, - "bytes": 558136, + "accessed": 1793064906, + "bytes": 200600, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/850739edc68b26c9", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/6b051e0a97b8b911", "files": 12, - "key": "850739edc68b26c9", + "key": "6b051e0a97b8b911", "kind": "pkg", "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792967289, + "accessed": 1793030359, "bytes": 558120, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/e50868c6827dcec0", @@ -372,34 +372,34 @@ "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792274406, - "bytes": 208104, + "accessed": 1793044985, + "bytes": 558088, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/80285723e6498f56", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/9588ad68bcf26d15", "files": 12, - "key": "80285723e6498f56", + "key": "9588ad68bcf26d15", "kind": "pkg", "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792204194, - "bytes": 935944, + "accessed": 1793053112, + "bytes": 704184, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xext@1.3.7/e8d0e90488045dfd", - "files": 18, - "key": "e8d0e90488045dfd", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/0639bd78ab4d2be9", + "files": 12, + "key": "0639bd78ab4d2be9", "kind": "pkg", - "label": "compat/compat.xext@1.3.7" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1792967289, - "bytes": 935920, + "accessed": 1793033974, + "bytes": 558216, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xext@1.3.7/79cf64f40d7c88d0", - "files": 18, - "key": "79cf64f40d7c88d0", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/cfbe3199c7e4e098", + "files": 12, + "key": "cfbe3199c7e4e098", "kind": "pkg", - "label": "compat/compat.xext@1.3.7" + "label": "compat/compat.xcb@1.17.0" } ], "root": "@HOME@/.mcpp/build-cache/v1" @@ -413,7 +413,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 -} \ No newline at end of file +} diff --git a/protocol/fixtures/index-list.json b/protocol/fixtures/index-list.json index ee3aee2..a77da76 100644 --- a/protocol/fixtures/index-list.json +++ b/protocol/fixtures/index-list.json @@ -21,7 +21,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/launch.json b/protocol/fixtures/launch.json index 09d9f75..d3f7212 100644 --- a/protocol/fixtures/launch.json +++ b/protocol/fixtures/launch.json @@ -1,7 +1,7 @@ { "data": { "argv": [ - "@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/bin/app" + "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app" ], "cwd": "@ROOT@", "env": { @@ -10,7 +10,7 @@ "XDG_DATA_DIRS": "@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop", "__EGL_VENDOR_LIBRARY_DIRS": "@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d" }, - "program": "@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/bin/app", + "program": "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app", "via": null }, "diagnostics": [], @@ -25,7 +25,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/pack-formats.json b/protocol/fixtures/pack-formats.json index 486c0c3..8bc6c2a 100644 --- a/protocol/fixtures/pack-formats.json +++ b/protocol/fixtures/pack-formats.json @@ -27,7 +27,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/protocol-version.json b/protocol/fixtures/protocol-version.json index 5131f4b..c12f108 100644 --- a/protocol/fixtures/protocol-version.json +++ b/protocol/fixtures/protocol-version.json @@ -114,7 +114,7 @@ "mcpp.xpkg": 1 }, "mcpp": { - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/result-ok.json b/protocol/fixtures/result-ok.json index 1477a87..f75dcad 100644 --- a/protocol/fixtures/result-ok.json +++ b/protocol/fixtures/result-ok.json @@ -5,7 +5,7 @@ "kind": "bin", "launch": { "argv": [ - "@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/bin/app" + "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app" ], "cwd": "@ROOT@", "env": { @@ -17,28 +17,28 @@ "via": null }, "name": "app", - "path": "@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/bin/app" + "path": "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app" } ], "client": "mcpp-ide-fixtures", "command": "mcpp build --message-format json", - "compileDatabase": "@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d/compile_commands.json", + "compileDatabase": "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/compile_commands.json", "configuration": { - "fingerprint": "b95fa85150d74e3d", - "outputDir": "@ROOT@/target/x86_64-linux-gnu/b95fa85150d74e3d", + "fingerprint": "b4dbdb186bc3ef30", + "outputDir": "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30", "profile": "dev", "triple": "x86_64-linux-gnu" }, "diagnostics": [], - "finishedAt": 1792988794753, - "pid": 1110202, - "startedAt": 1792988793983, + "finishedAt": 1793118343698, + "pid": 1767942, + "startedAt": 1793118343022, "status": "ok" }, "kind": "mcpp.result", "kindVersion": 1, "mcpp": { - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/search.json b/protocol/fixtures/search.json index a9c7b5c..9dfce35 100644 --- a/protocol/fixtures/search.json +++ b/protocol/fixtures/search.json @@ -3,7 +3,7 @@ "keyword": "", "packages": [ { - "description": "Boost as C++23 named modules \u2014 import boost.; or the umbrella import boost;", + "description": "Boost as C++23 named modules — import boost.; or the umbrella import boost;", "id": "ZheFeng7110:boost", "index": "mcpplibs", "licenses": [ @@ -32,7 +32,7 @@ ] }, { - "description": " \u53bb\u4e2d\u5fc3\u5316\u7684 [ XIM\u5305\u7d22\u5f15\u4ed3\u5e93\u5217\u8868 ] \u7d22\u5f15\u4ed3\u5e93 Decentralized [XIM Package Index Repository List] index repository ", + "description": " 去中心化的 [ XIM包索引仓库列表 ] 索引仓库 Decentralized [XIM Package Index Repository List] index repository ", "id": "awesome:awesome", "index": "mcpplibs", "licenses": [], @@ -118,7 +118,7 @@ "versions": [] }, { - "description": "[Boost::ext].UT \u2014 C++20 single-header unit testing framework, exposed as the C++23 module boost.ut", + "description": "[Boost::ext].UT — C++20 single-header unit testing framework, exposed as the C++23 module boost.ut", "id": "boost-ext:ut", "index": "mcpplibs", "licenses": [ @@ -160,7 +160,7 @@ ] }, { - "description": "Abseil \u2014 Google's C++ common libraries (LTS 20250512.1, static)", + "description": "Abseil — Google's C++ common libraries (LTS 20250512.1, static)", "id": "compat:abseil", "index": "mcpplibs", "licenses": [ @@ -189,7 +189,7 @@ ] }, { - "description": "argparse \u2014 header-only argument parser for modern C++", + "description": "argparse — header-only argument parser for modern C++", "id": "compat:argparse", "index": "mcpplibs", "licenses": [ @@ -203,7 +203,7 @@ ] }, { - "description": "Boost.Align 1.92.0 \u2014 aligned allocation functions, allocators and traits", + "description": "Boost.Align 1.92.0 — aligned allocation functions, allocators and traits", "id": "compat:boost-align", "index": "mcpplibs", "licenses": [ @@ -217,7 +217,7 @@ ] }, { - "description": "Boost.Any 1.92.0 \u2014 a type-safe container for single values of different types", + "description": "Boost.Any 1.92.0 — a type-safe container for single values of different types", "id": "compat:boost-any", "index": "mcpplibs", "licenses": [ @@ -231,7 +231,7 @@ ] }, { - "description": "Boost.Asio 1.92.0 \u2014 networking/async I/O; the boostorg tree consumed by Boost.Beast", + "description": "Boost.Asio 1.92.0 — networking/async I/O; the boostorg tree consumed by Boost.Beast", "id": "compat:boost-asio", "index": "mcpplibs", "licenses": [ @@ -245,7 +245,7 @@ ] }, { - "description": "Boost.Assert 1.92.0 \u2014 configurable assert macros with source-location support", + "description": "Boost.Assert 1.92.0 — configurable assert macros with source-location support", "id": "compat:boost-assert", "index": "mcpplibs", "licenses": [ @@ -259,7 +259,7 @@ ] }, { - "description": "Boost.Beast 1.92.0 \u2014 HTTP and WebSocket networking on Boost.Asio (header-only)", + "description": "Boost.Beast 1.92.0 — HTTP and WebSocket networking on Boost.Asio (header-only)", "id": "compat:boost-beast", "index": "mcpplibs", "licenses": [ @@ -273,7 +273,7 @@ ] }, { - "description": "Boost.Bind 1.92.0 \u2014 bind.hpp expression binders and mem_fn", + "description": "Boost.Bind 1.92.0 — bind.hpp expression binders and mem_fn", "id": "compat:boost-bind", "index": "mcpplibs", "licenses": [ @@ -287,7 +287,7 @@ ] }, { - "description": "Boost.CircularBuffer 1.92.0 \u2014 a STL-compatible ring buffer container", + "description": "Boost.CircularBuffer 1.92.0 — a STL-compatible ring buffer container", "id": "compat:boost-circular-buffer", "index": "mcpplibs", "licenses": [ @@ -301,7 +301,7 @@ ] }, { - "description": "Boost.Compat 1.92.0 \u2014 C++11-17 backports of newer standard facilities (invoke, to_chars)", + "description": "Boost.Compat 1.92.0 — C++11-17 backports of newer standard facilities (invoke, to_chars)", "id": "compat:boost-compat", "index": "mcpplibs", "licenses": [ @@ -315,7 +315,7 @@ ] }, { - "description": "Boost.ConceptCheck 1.92.0 \u2014 compile-time checks for C++ concepts and requirements", + "description": "Boost.ConceptCheck 1.92.0 — compile-time checks for C++ concepts and requirements", "id": "compat:boost-concept-check", "index": "mcpplibs", "licenses": [ @@ -329,7 +329,7 @@ ] }, { - "description": "Boost.Config 1.92.0 \u2014 platform/compiler/stdlib detection macros; root of the modular-boost header family", + "description": "Boost.Config 1.92.0 — platform/compiler/stdlib detection macros; root of the modular-boost header family", "id": "compat:boost-config", "index": "mcpplibs", "licenses": [ @@ -343,7 +343,7 @@ ] }, { - "description": "Boost.Container 1.92.0 \u2014 STL-compatible containers; Beast consumes allocator_traits", + "description": "Boost.Container 1.92.0 — STL-compatible containers; Beast consumes allocator_traits", "id": "compat:boost-container", "index": "mcpplibs", "licenses": [ @@ -357,7 +357,7 @@ ] }, { - "description": "Boost.ContainerHash 1.92.0 \u2014 hash_value and hash range combinators", + "description": "Boost.ContainerHash 1.92.0 — hash_value and hash range combinators", "id": "compat:boost-container-hash", "index": "mcpplibs", "licenses": [ @@ -371,7 +371,7 @@ ] }, { - "description": "Boost.Core 1.92.0 \u2014 core utilities: addressof, empty_value, ref, type.hpp shims", + "description": "Boost.Core 1.92.0 — core utilities: addressof, empty_value, ref, type.hpp shims", "id": "compat:boost-core", "index": "mcpplibs", "licenses": [ @@ -385,7 +385,7 @@ ] }, { - "description": "Boost.Describe 1.92.0 \u2014 macro-based enum/class descriptions (feeds ContainerHash)", + "description": "Boost.Describe 1.92.0 — macro-based enum/class descriptions (feeds ContainerHash)", "id": "compat:boost-describe", "index": "mcpplibs", "licenses": [ @@ -399,7 +399,7 @@ ] }, { - "description": "Boost.Endian 1.92.0 \u2014 byte-order conversion (WebSocket framing)", + "description": "Boost.Endian 1.92.0 — byte-order conversion (WebSocket framing)", "id": "compat:boost-endian", "index": "mcpplibs", "licenses": [ @@ -413,7 +413,7 @@ ] }, { - "description": "Boost.Intrusive 1.92.0 \u2014 intrusive list/set hooks (Beast buffers and http::fields)", + "description": "Boost.Intrusive 1.92.0 — intrusive list/set hooks (Beast buffers and http::fields)", "id": "compat:boost-intrusive", "index": "mcpplibs", "licenses": [ @@ -427,7 +427,7 @@ ] }, { - "description": "Boost.IO 1.92.0 \u2014 stream flag helpers (ios_state, ostream_put) and boost/io_fwd.hpp", + "description": "Boost.IO 1.92.0 — stream flag helpers (ios_state, ostream_put) and boost/io_fwd.hpp", "id": "compat:boost-io", "index": "mcpplibs", "licenses": [ @@ -441,7 +441,7 @@ ] }, { - "description": "Boost.Logic 1.92.0 \u2014 tribool three-state boolean (Beast detect_ssl)", + "description": "Boost.Logic 1.92.0 — tribool three-state boolean (Beast detect_ssl)", "id": "compat:boost-logic", "index": "mcpplibs", "licenses": [ @@ -455,7 +455,7 @@ ] }, { - "description": "Boost.Move 1.92.0 \u2014 move-emulation traits and move-aware utilities", + "description": "Boost.Move 1.92.0 — move-emulation traits and move-aware utilities", "id": "compat:boost-move", "index": "mcpplibs", "licenses": [ @@ -469,7 +469,7 @@ ] }, { - "description": "Boost.Mp11 1.92.0 \u2014 C++11 metaprogramming list/combinator library", + "description": "Boost.Mp11 1.92.0 — C++11 metaprogramming list/combinator library", "id": "compat:boost-mp11", "index": "mcpplibs", "licenses": [ @@ -483,7 +483,7 @@ ] }, { - "description": "Boost.Optional 1.92.0 \u2014 optional values (Beast buffers_prefix uses in_place_init)", + "description": "Boost.Optional 1.92.0 — optional values (Beast buffers_prefix uses in_place_init)", "id": "compat:boost-optional", "index": "mcpplibs", "licenses": [ @@ -497,7 +497,7 @@ ] }, { - "description": "Boost.Predef 1.92.0 \u2014 compiler/architecture/OS detection macros (feeds WinAPI)", + "description": "Boost.Predef 1.92.0 — compiler/architecture/OS detection macros (feeds WinAPI)", "id": "compat:boost-predef", "index": "mcpplibs", "licenses": [ @@ -511,7 +511,7 @@ ] }, { - "description": "Boost.Preprocessor 1.92.0 \u2014 preprocessor metaprogramming (feeds Utility/TypeTraits)", + "description": "Boost.Preprocessor 1.92.0 — preprocessor metaprogramming (feeds Utility/TypeTraits)", "id": "compat:boost-preprocessor", "index": "mcpplibs", "licenses": [ @@ -525,7 +525,7 @@ ] }, { - "description": "Boost.SmartPtr 1.92.0 \u2014 shared/weak/scoped pointers plus boost/shared_ptr.hpp shims", + "description": "Boost.SmartPtr 1.92.0 — shared/weak/scoped pointers plus boost/shared_ptr.hpp shims", "id": "compat:boost-smart-ptr", "index": "mcpplibs", "licenses": [ @@ -539,7 +539,7 @@ ] }, { - "description": "Boost.StaticString 1.92.0 \u2014 fixed-capacity string behind beast::static_string", + "description": "Boost.StaticString 1.92.0 — fixed-capacity string behind beast::static_string", "id": "compat:boost-static-string", "index": "mcpplibs", "licenses": [ @@ -553,7 +553,7 @@ ] }, { - "description": "Boost.System 1.92.0 \u2014 error_code/system_error and the boost/cerrno.hpp shim", + "description": "Boost.System 1.92.0 — error_code/system_error and the boost/cerrno.hpp shim", "id": "compat:boost-system", "index": "mcpplibs", "licenses": [ @@ -567,7 +567,7 @@ ] }, { - "description": "Boost.ThrowException 1.92.0 \u2014 common exception-raising infrastructure for Boost libraries", + "description": "Boost.ThrowException 1.92.0 — common exception-raising infrastructure for Boost libraries", "id": "compat:boost-throw-exception", "index": "mcpplibs", "licenses": [ @@ -581,7 +581,7 @@ ] }, { - "description": "Boost.TypeIndex 1.92.0 \u2014 runtime type information with RTTI-free fallback", + "description": "Boost.TypeIndex 1.92.0 — runtime type information with RTTI-free fallback", "id": "compat:boost-type-index", "index": "mcpplibs", "licenses": [ @@ -595,7 +595,7 @@ ] }, { - "description": "Boost.TypeTraits 1.92.0 \u2014 compile-time type introspection traits", + "description": "Boost.TypeTraits 1.92.0 — compile-time type introspection traits", "id": "compat:boost-type-traits", "index": "mcpplibs", "licenses": [ @@ -609,7 +609,7 @@ ] }, { - "description": "Boost.Utility 1.92.0 \u2014 result_of, compressed_pair, call_traits, in_place factories", + "description": "Boost.Utility 1.92.0 — result_of, compressed_pair, call_traits, in_place factories", "id": "compat:boost-utility", "index": "mcpplibs", "licenses": [ @@ -623,7 +623,7 @@ ] }, { - "description": "Boost.UUID 1.92.0 \u2014 RFC 4122/9562 UUID generation and parsing", + "description": "Boost.UUID 1.92.0 — RFC 4122/9562 UUID generation and parsing", "id": "compat:boost-uuid", "index": "mcpplibs", "licenses": [ @@ -637,7 +637,7 @@ ] }, { - "description": "Boost.Variant2 1.92.0 \u2014 never-empty variant (feeds Boost.System's result)", + "description": "Boost.Variant2 1.92.0 — never-empty variant (feeds Boost.System's result)", "id": "compat:boost-variant2", "index": "mcpplibs", "licenses": [ @@ -651,7 +651,7 @@ ] }, { - "description": "Boost.WinAPI 1.92.0 \u2014 WinAPI wrappers; owns boost/detail/winapi/* shims too", + "description": "Boost.WinAPI 1.92.0 — WinAPI wrappers; owns boost/detail/winapi/* shims too", "id": "compat:boost-winapi", "index": "mcpplibs", "licenses": [ @@ -693,7 +693,7 @@ ] }, { - "description": "c-ares \u2014 asynchronous DNS resolver library (static)", + "description": "c-ares — asynchronous DNS resolver library (static)", "id": "compat:c-ares", "index": "mcpplibs", "licenses": [ @@ -736,7 +736,7 @@ ] }, { - "description": "moodycamel::ConcurrentQueue \u2014 lock-free MPMC queue (header-only)", + "description": "moodycamel::ConcurrentQueue — lock-free MPMC queue (header-only)", "id": "compat:concurrentqueue", "index": "mcpplibs", "licenses": [ @@ -751,7 +751,7 @@ ] }, { - "description": "cpptrace \u2014 simple, portable stack traces for C++", + "description": "cpptrace — simple, portable stack traces for C++", "id": "compat:cpptrace", "index": "mcpplibs", "licenses": [ @@ -853,7 +853,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 -} \ No newline at end of file +} diff --git a/protocol/fixtures/self-env.json b/protocol/fixtures/self-env.json index 747c581..165eaa0 100644 --- a/protocol/fixtures/self-env.json +++ b/protocol/fixtures/self-env.json @@ -4,12 +4,12 @@ "buildCache": "@HOME@/.mcpp/build-cache/v1", "config": "@HOME@/.mcpp/config.toml", "defaultToolchain": "gcc@16.1.0", - "engineModules": "@HOME@/.mcpp/engine/2026.10.26.1/modules", + "engineModules": "@HOME@/.mcpp/engine/2026.10.26.2/modules", "homeLocator": "", "homeSource": "user", "initialized": true, "mcppHome": "@HOME@/.mcpp", - "mcppVersion": "2026.10.26.1", + "mcppVersion": "2026.10.26.2", "originalHome": "@HOME@/.mcpp", "registry": "@HOME@/.mcpp/registry", "xlingsBinary": "@HOME@/.mcpp/registry/bin/xlings", @@ -24,7 +24,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/test-list.ndjson b/protocol/fixtures/test-list.ndjson new file mode 100644 index 0000000..88c6863 --- /dev/null +++ b/protocol/fixtures/test-list.ndjson @@ -0,0 +1,2 @@ +{"member":"","test":"test_smoke","main":"@ROOT@/tests/test_smoke.cpp"} +{"summary":{"total":1}} diff --git a/protocol/fixtures/test.ndjson b/protocol/fixtures/test.ndjson index c357c97..ebcea38 100644 --- a/protocol/fixtures/test.ndjson +++ b/protocol/fixtures/test.ndjson @@ -1,2 +1,2 @@ -{"member":"","test":"test_smoke","status":"pass","exit_code":0,"signal":null,"duration_ms":20,"timed_out":false,"compile_output":"","run_output":"test_smoke: ok\n","reason":"","build_ms":615} -{"summary":{"member":"","passed":1,"failed":0,"not_run":0,"not_run_reason":"","built":0,"elapsed_ms":1316,"build_ms":668,"run_ms":20}} +{"member":"","test":"test_smoke","status":"pass","exit_code":0,"signal":null,"duration_ms":2,"timed_out":false,"compile_output":"","run_output":"test_smoke: ok\n","reason":"","build_ms":616} +{"summary":{"member":"","passed":1,"failed":0,"not_run":0,"not_run_reason":"","built":0,"elapsed_ms":778,"build_ms":672,"run_ms":2}} diff --git a/protocol/fixtures/toolchain-list.json b/protocol/fixtures/toolchain-list.json index d519a56..b9d72e1 100644 --- a/protocol/fixtures/toolchain-list.json +++ b/protocol/fixtures/toolchain-list.json @@ -90,6 +90,14 @@ "target": "aarch64-none-elf", "toolchain": "llvm 23.1.3" }, + { + "default": false, + "note": "ok, static, cross", + "pin": "llvm@23.1.3", + "status": "available", + "target": "aarch64-openkal", + "toolchain": "llvm 23.1.3" + }, { "default": false, "note": "bare, static, cross", @@ -202,6 +210,14 @@ "target": "x86_64-none-elf", "toolchain": "llvm 23.1.3" }, + { + "default": false, + "note": "ok, static, cross", + "pin": "llvm@23.1.3", + "status": "available", + "target": "x86_64-openkal", + "toolchain": "llvm 23.1.3" + }, { "default": false, "note": "PE, static, cross", @@ -262,7 +278,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.1" + "version": "2026.10.26.2" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/version.txt b/protocol/fixtures/version.txt index 08c2962..9b0c5c9 100644 --- a/protocol/fixtures/version.txt +++ b/protocol/fixtures/version.txt @@ -1 +1 @@ -mcpp 2026.10.26.1 +mcpp 2026.10.26.2 diff --git a/protocol/mcpp-contract.schema.json b/protocol/mcpp-contract.schema.json new file mode 100644 index 0000000..5e32232 --- /dev/null +++ b/protocol/mcpp-contract.schema.json @@ -0,0 +1,372 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/mcpp-community/mcpp-ide/protocol/mcpp-contract.schema.json", + "title": "The part of mcpp's control contract the mcpp-ide backend reads", + "description": "mcpp docs/50. Every document under protocol/fixtures is checked against the definition protocol/fixtures.json names for it; a field the backend reads and mcpp stops writing fails that check. Additional fields are allowed: the contract grows.", + "$defs": { + "mcppStamp": { + "type": "object", + "required": ["version"], + "properties": { + "version": { "type": "string" }, + "protocol": { "type": "object", "properties": { "min": { "type": "integer" }, "max": { "type": "integer" } } } + } + }, + "position": { + "type": "object", + "required": ["line", "column"], + "properties": { "line": { "type": "integer", "minimum": 0 }, "column": { "type": "integer", "minimum": 0 } } + }, + "diagnostic": { + "type": "object", + "required": ["message"], + "properties": { + "severity": { "enum": ["error", "warning", "note", "info", "help"] }, + "message": { "type": "string" }, + "code": { "type": "string" }, + "path": { "type": "string" }, + "source": { "type": "string" }, + "range": { + "type": "object", + "required": ["start", "end"], + "properties": { "start": { "$ref": "#/$defs/position" }, "end": { "$ref": "#/$defs/position" } } + } + } + }, + "envelope": { + "type": "object", + "required": ["schemaVersion", "kind"], + "properties": { + "schemaVersion": { "const": 1 }, + "kind": { "type": "string" }, + "kindVersion": { "type": "integer" }, + "diagnostics": { "type": "array", "items": { "$ref": "#/$defs/diagnostic" } }, + "effects": { "type": "array", "items": { "type": "string" } }, + "mcpp": { "$ref": "#/$defs/mcppStamp" } + } + }, + "configuration": { + "type": "object", + "required": ["fingerprint", "outputDir", "profile", "triple"], + "properties": { + "fingerprint": { "type": "string" }, + "outputDir": { "type": "string" }, + "profile": { "type": "string" }, + "triple": { "type": "string" } + } + }, + "platformField": { + "type": "object", + "properties": { "value": {}, "source": { "type": "string" } } + }, + "platform": { + "description": "The platform that configures a target (mcpp design 2026-10-28 §9): its name and version, where the choice came from, and each field with its value and source. Null where mcpp reports none.", + "type": ["object", "null"], + "properties": { + "name": { "type": "string" }, + "version": { "type": ["string", "null"] }, + "source": { "type": "string" }, + "fields": { "type": "object", "additionalProperties": { "$ref": "#/$defs/platformField" } } + } + }, + "launch": { + "type": "object", + "required": ["argv", "cwd", "env"], + "properties": { + "argv": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "cwd": { "type": "string" }, + "env": { "type": "object", "additionalProperties": { "type": "string" } }, + "program": { "type": "string" }, + "via": { "type": ["string", "null"] } + } + }, + "artifact": { + "type": "object", + "required": ["kind", "name", "path"], + "properties": { + "kind": { "type": "string" }, + "name": { "type": "string" }, + "path": { "type": "string" }, + "launch": { "$ref": "#/$defs/launch" } + } + }, + "event": { + "type": "object", + "required": ["kind", "event", "schemaVersion"], + "properties": { + "kind": { "const": "mcpp.event" }, + "schemaVersion": { "const": 1 }, + "event": { "enum": ["plan", "progress", "diagnostic", "artifact", "step", "status"] }, + "configuration": { "$ref": "#/$defs/configuration" }, + "platform": { "$ref": "#/$defs/platform" }, + "hostPlatform": { "$ref": "#/$defs/platform" }, + "finished": { "type": "integer" }, + "total": { "type": "integer" }, + "diagnostic": { "$ref": "#/$defs/diagnostic" }, + "artifact": { "$ref": "#/$defs/artifact" } + } + }, + "resultData": { + "type": "object", + "required": ["status", "command", "configuration"], + "properties": { + "status": { "enum": ["ok", "failed", "cancelled", "denied", "running"] }, + "command": { "type": "string" }, + "client": { "type": "string" }, + "configuration": { "$ref": "#/$defs/configuration" }, + "artifacts": { "type": "array", "items": { "$ref": "#/$defs/artifact" } }, + "compileDatabase": { "type": ["string", "null"] }, + "diagnostics": { "type": "array", "items": { "$ref": "#/$defs/diagnostic" } }, + "startedAt": { "type": "integer" }, + "finishedAt": { "type": ["integer", "null"] } + } + }, + "buildEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { "properties": { "kind": { "const": "mcpp.build" }, "data": { "$ref": "#/$defs/resultData" } } } + ] + }, + "buildStreamLine": { + "anyOf": [ { "$ref": "#/$defs/event" }, { "$ref": "#/$defs/buildEnvelope" } ] + }, + "resultRecord": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { "required": ["data"], "properties": { "data": { "$ref": "#/$defs/resultData" } } } + ] + }, + "launchEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { "required": ["data"], "properties": { "kind": { "const": "mcpp.launch" }, "data": { "$ref": "#/$defs/launch" } } } + ] + }, + "testRecord": { + "type": "object", + "required": ["test", "status"], + "properties": { + "member": { "type": "string" }, + "test": { "type": "string" }, + "status": { "enum": ["pass", "fail", "skip", "not_run", "error"] }, + "exit_code": { "type": ["integer", "null"] }, + "duration_ms": { "type": "integer" }, + "timed_out": { "type": "boolean" }, + "compile_output": { "type": "string" }, + "run_output": { "type": "string" }, + "reason": { "type": "string" } + } + }, + "testSummary": { + "type": "object", + "required": ["summary"], + "properties": { + "summary": { + "type": "object", + "properties": { + "passed": { "type": "integer" }, + "failed": { "type": "integer" }, + "not_run": { "type": "integer" }, + "total": { "type": "integer" }, + "elapsed_ms": { "type": "integer" } + } + } + } + }, + "testStreamLine": { "anyOf": [ { "$ref": "#/$defs/testRecord" }, { "$ref": "#/$defs/testSummary" } ] }, + "testListLine": { + "anyOf": [ + { "type": "object", "required": ["test"], "properties": { "test": { "type": "string" }, "member": { "type": "string" }, "main": { "type": "string" } } }, + { "$ref": "#/$defs/testSummary" } + ] + }, + "buildDatabaseEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { + "required": ["data"], + "properties": { + "kind": { "const": "mcpp.build-database" }, + "data": { + "type": "object", + "required": ["database"], + "properties": { + "database": { + "type": "object", + "required": ["sets"], + "properties": { + "sets": { + "type": "array", + "items": { + "type": "object", + "required": ["name"], + "properties": { + "name": { "type": "string" }, + "visible-sets": { "type": "array", "items": { "type": "string" } }, + "ide": { "type": "object", "properties": { "kind": { "type": "string" }, "configuration": { "type": "string" } } }, + "translation-units": { + "type": "array", + "items": { + "type": "object", + "required": ["source"], + "properties": { + "source": { "type": "string" }, + "provides": { "type": "object" }, + "requires": { "type": "array", "items": { "type": "string" } } + } + } + } + } + } + } + } + } + } + } + } + } + ] + }, + "toolchainRow": { + "type": "object", + "required": ["target", "toolchain", "status"], + "properties": { + "target": { "type": "string" }, + "toolchain": { "type": "string" }, + "pin": { "type": "string" }, + "status": { "type": "string" }, + "default": { "type": "boolean" }, + "note": { "type": "string" }, + "platform": { "$ref": "#/$defs/platform" } + } + }, + "toolchainListEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { + "required": ["data"], + "properties": { + "kind": { "const": "mcpp.toolchain.list" }, + "data": { + "type": "object", + "required": ["host", "targets"], + "properties": { + "host": { "type": "string" }, + "targets": { "type": "array", "items": { "$ref": "#/$defs/toolchainRow" } }, + "hostPlatform": { "$ref": "#/$defs/platform" } + } + } + } + } + ] + }, + "searchEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { + "required": ["data"], + "properties": { + "kind": { "const": "mcpp.search" }, + "data": { + "type": "object", + "required": ["packages"], + "properties": { + "packages": { + "type": "array", + "items": { + "type": "object", + "required": ["id", "name", "index", "versions"], + "properties": { + "id": { "type": "string" }, + "name": { "type": "string" }, + "namespace": { "type": "string" }, + "index": { "type": "string" }, + "description": { "type": "string" }, + "versions": { "type": "array", "items": { "type": "string" } } + } + } + } + } + } + } + } + ] + }, + "cacheListEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { + "required": ["data"], + "properties": { + "kind": { "const": "mcpp.cache" }, + "data": { + "type": "object", + "required": ["entries"], + "properties": { + "entries": { + "type": "array", + "items": { + "type": "object", + "required": ["kind", "label", "bytes"], + "properties": { + "kind": { "type": "string" }, + "label": { "type": "string" }, + "bytes": { "type": "integer" }, + "accessed": { "type": "integer" }, + "complete": { "type": "boolean" }, + "dir": { "type": "string" } + } + } + } + } + } + } + } + ] + }, + "indexListEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { "required": ["data"], "properties": { "kind": { "const": "mcpp.index" }, "data": { "type": "object", "required": ["registries"] } } } + ] + }, + "packFormatsEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { + "required": ["data"], + "properties": { + "kind": { "const": "mcpp.pack.formats" }, + "data": { + "type": "object", + "required": ["formats"], + "properties": { + "formats": { + "type": "array", + "items": { "type": "object", "required": ["name"], "properties": { "name": { "type": "string" }, "builtin": { "type": "boolean" } } } + } + } + } + } + } + ] + }, + "selfEnvEnvelope": { + "allOf": [ + { "$ref": "#/$defs/envelope" }, + { "required": ["data"], "properties": { "kind": { "const": "mcpp.env" }, "data": { "type": "object", "required": ["mcppVersion", "mcppHome"] } } } + ] + }, + "protocolVersion": { + "type": "object", + "required": ["kind", "kinds", "mcpp", "envelope"], + "properties": { + "kind": { "const": "mcpp.protocol" }, + "kinds": { "type": "object", "additionalProperties": { "type": "integer" } }, + "commands": { "type": "object" }, + "envelope": { "type": "object", "required": ["min", "max"] }, + "mcpp": { "$ref": "#/$defs/mcppStamp" } + } + } + } +} diff --git a/protocol/protocol.schema.json b/protocol/protocol.schema.json new file mode 100644 index 0000000..1bd2d65 --- /dev/null +++ b/protocol/protocol.schema.json @@ -0,0 +1,352 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://github.com/mcpp-community/mcpp-ide/protocol/protocol.schema.json", + "title": "The mcpp-ide protocol", + "description": "JSON-RPC 2.0 over the LSP base protocol (Content-Length framing) on the standard streams of `mcpp-ide serve`. Version 1. An adapter sends `initialize` first; every other request before it is refused (-32002). Requests run concurrently; `$/cancelRequest` cancels one. The backend's tests check that the methods it registers and the notifications it sends are exactly the ones listed here.", + "version": 1, + "methods": { + "initialize": { + "description": "Starts the session: finds mcpp and mcppls, resolves the settings, discovers the projects of the folders and watches them.", + "params": { + "type": "object", + "properties": { + "client": { "type": "object", "properties": { "name": { "type": "string" }, "version": { "type": "string" } } }, + "editor": { "enum": ["vscode", "jetbrains", "cli"] }, + "locale": { "type": "string" }, + "trusted": { "type": "boolean" }, + "settings": { "$ref": "#/$defs/settingValues" }, + "workspaceFolders": { "type": "array", "items": { "type": "string" } }, + "languageService": { "type": "object", "properties": { "candidates": { "type": "array", "items": { "type": "string" } } } } + } + }, + "result": { + "type": "object", + "required": ["server", "protocol", "projects", "capabilities", "checks"], + "properties": { + "server": { "type": "object", "required": ["name", "version"] }, + "protocol": { "const": 1 }, + "mcpp": { "type": ["object", "null"] }, + "languageService": { "$ref": "#/$defs/languageService" }, + "checks": { "type": "array", "items": { "$ref": "#/$defs/check" } }, + "projects": { "type": "array", "items": { "$ref": "#/$defs/project" } }, + "capabilities": { "type": "array", "items": { "type": "string" } } + } + } + }, + "settings/update": { + "description": "The adapter's settings changed: they are validated, migrated from earlier keys and resolved.", + "params": { "type": "object", "properties": { "settings": { "$ref": "#/$defs/settingValues" }, "trusted": { "type": "boolean" }, "locale": { "type": "string" } } }, + "result": { "$ref": "#/$defs/resolvedSettings" } + }, + "settings/registry": { + "description": "Every setting with its type, default, bounds, group and texts, and the presets: what a settings panel renders.", + "params": { "type": "object" }, + "result": { "type": "object", "required": ["settings", "presets"] } + }, + "settings/preset": { + "params": { "type": "object", "required": ["id"], "properties": { "id": { "type": "string" } } }, + "result": { "type": "object" } + }, + "i18n/bundle": { + "description": "The runtime strings in a language, keyed by their English text ({} for English).", + "params": { "type": "object", "properties": { "locale": { "type": "string" } } }, + "result": { "type": "object", "additionalProperties": { "type": "string" } } + }, + "selfCheck": { + "description": "Finds mcpp again and reports what the backend finds: the backend, mcpp and its contract, mcppls, xlings, trust.", + "params": { "type": "object" }, + "result": { "type": "object", "required": ["backend", "checks"], "properties": { "checks": { "type": "array", "items": { "$ref": "#/$defs/check" } } } } + }, + "commands/list": { + "description": "The command table (spec/commands.json) for one editor, with titles in the session's language.", + "params": { "type": "object", "properties": { "editor": { "enum": ["vscode", "jetbrains", "cli"] } } }, + "result": { "type": "object", "required": ["commands"], "properties": { "commands": { "type": "array", "items": { "$ref": "#/$defs/command" } } } } + }, + "menu/quick": { + "description": "The quick menu for a project: each item enabled or not, with the reason.", + "params": { "type": "object", "properties": { "root": { "type": "string" }, "editor": { "type": "string" } } }, + "result": { + "type": "object", + "required": ["items"], + "properties": { + "items": { + "type": "array", + "items": { + "type": "object", + "required": ["command", "title", "enabled"], + "properties": { "command": { "type": "string" }, "title": { "type": "string" }, "group": { "type": "string" }, "enabled": { "type": "boolean" }, "reason": { "type": "string" }, "detail": { "type": "string" } } + } + } + } + } + }, + "languageService/status": { + "description": "Which mcppls answers this editor's C++ files and whether it reads mcpp's result record (0.0.18 and later). Candidates are the servers the adapter knows of (the mcppls extension's or plugin's own); PATH, xlings and the plugin payload follow.", + "params": { "type": "object", "properties": { "candidates": { "type": "array", "items": { "type": "string" } } } }, + "result": { "$ref": "#/$defs/languageService" } + }, + "projects/list": { + "params": { "type": "object", "properties": { "folders": { "type": "array", "items": { "type": "string" } }, "depth": { "type": "integer" } } }, + "result": { "type": "array", "items": { "$ref": "#/$defs/project" } } + }, + "projects/forFile": { + "description": "The project a file belongs to: the nearest mcpp.toml above it, no higher than the boundary.", + "params": { "type": "object", "required": ["path"], "properties": { "path": { "type": "string" }, "boundary": { "type": "string" } } }, + "result": { "anyOf": [ { "$ref": "#/$defs/project" }, { "type": "null" } ] } + }, + "project/summary": { + "description": "A project's executables, tests, libraries, toolchain, last build, and the platforms its last plan named.", + "params": { "$ref": "#/$defs/rooted" }, + "result": { + "type": "object", + "required": ["root", "targets", "tests", "libraries"], + "properties": { + "root": { "type": "string" }, + "targets": { "type": "array" }, + "tests": { "type": "array" }, + "libraries": { "type": "array" }, + "toolchain": { "type": "string" }, + "target": {}, + "lastBuild": { "type": "object" }, + "artifacts": { "type": "array" }, + "platform": { "$ref": "#/$defs/platform" }, + "platformText": { "type": "string" }, + "hostPlatform": { "$ref": "#/$defs/platform" }, + "hostPlatformText": { "type": "string" }, + "error": { "type": "string" } + } + } + }, + "project/new": { + "description": "`mcpp new ` in a parent directory, as a job; the result names the new project's root.", + "params": { "type": "object", "required": ["parent", "name"], "properties": { "parent": { "type": "string" }, "name": { "type": "string" }, "template": { "type": "string" } } }, + "result": { "type": "object", "required": ["jobId", "root"] } + }, + "result/last": { + "description": "The result record target/.last-result.json names, or null.", + "params": { "$ref": "#/$defs/rooted" }, + "result": { "type": ["object", "null"] } + }, + "job/start": { + "description": "Queues a job on its project's lane: one at a time per project, in order; a build or test asked for again replaces the waiting one, and `supersede` cancels the running one.", + "params": { + "type": "object", + "required": ["kind", "root"], + "properties": { + "kind": { "enum": ["build", "test", "pack", "toolchain", "add", "command"] }, + "root": { "type": "string" }, + "target": { "type": "string", "description": "The target triple; absent: the mcpp.build.target setting; empty: this machine." }, + "profile": { "enum": ["dev", "release"] }, + "filter": { "type": "string" }, + "format": { "type": "string" }, + "mode": { "type": "string" }, + "spec": { "type": "string" }, + "dependency": { "type": "string" }, + "args": { "type": "array", "items": { "type": "string" } }, + "supersede": { "type": "boolean" }, + "color": { "type": "boolean" } + } + }, + "result": { "$ref": "#/$defs/jobRef" } + }, + "job/cancel": { + "params": { "type": "object", "required": ["jobId"], "properties": { "jobId": { "type": "string" } } }, + "result": { "type": "object", "required": ["cancelled"], "properties": { "cancelled": { "type": "boolean" } } } + }, + "job/list": { + "params": { "type": "object" }, + "result": { "type": "array", "items": { "type": "object", "required": ["id", "kind", "root", "state"] } } + }, + "run/launch": { + "description": "Builds and returns how the program starts (mcpp run --print-launch): the adapter starts it in a terminal.", + "params": { "$ref": "#/$defs/launchParams" }, + "result": { "type": "object", "required": ["argv", "cwd", "env"], "properties": { "argv": { "type": "array", "items": { "type": "string" } }, "cwd": { "type": "string" }, "env": { "type": "object" }, "program": { "type": "string" }, "via": { "type": ["string", "null"] } } } + }, + "debug/configuration": { + "description": "Builds and returns a debug configuration for the adapter's debugger. A program that runs through another (an ok image under okrun) is debugged as that runner, its symbols read through the GDB JIT interface.", + "params": { + "allOf": [ + { "$ref": "#/$defs/launchParams" }, + { "properties": { "engine": { "enum": ["auto", "cppdbg", "lldb", "lldb-dap", "gdb"] }, "available": { "type": "array", "items": { "type": "string" } }, "platform": { "type": "string" } } } + ] + }, + "result": { "type": "object", "required": ["engine", "configuration", "launch"] } + }, + "test/list": { + "description": "The tests of a project without building them (mcpp test --list).", + "params": { "$ref": "#/$defs/rooted" }, + "result": { + "type": "object", + "required": ["root", "tests"], + "properties": { "tests": { "type": "array", "items": { "type": "object", "required": ["test"], "properties": { "test": { "type": "string" }, "member": { "type": "string" }, "main": { "type": "string" } } } } } + } + }, + "library/search": { + "params": { "type": "object", "properties": { "keyword": { "type": "string" }, "index": { "type": "string" }, "sort": { "enum": ["name", "versions"] }, "limit": { "type": "integer" }, "id": { "type": "string" }, "refresh": { "type": "boolean" }, "root": { "type": "string" } } }, + "result": { "type": "object" } + }, + "library/indexes": { "params": { "type": "object" }, "result": { "type": ["object", "null"] } }, + "library/add": { + "params": { "type": "object", "required": ["root", "dependency"], "properties": { "root": { "type": "string" }, "dependency": { "type": "string" }, "version": { "type": "string" } } }, + "result": { "$ref": "#/$defs/jobRef" } + }, + "library/updateIndex": { "params": { "type": "object" }, "result": { "$ref": "#/$defs/jobRef" } }, + "toolchains/list": { "params": { "type": "object" }, "result": { "type": "object", "required": ["host", "rows", "defaults"] } }, + "toolchains/install": { + "params": { "type": "object", "required": ["spec"], "properties": { "spec": { "type": "string" }, "target": { "type": "string" }, "root": { "type": "string" } } }, + "result": { "$ref": "#/$defs/jobRef" } + }, + "toolchains/setDefault": { + "params": { "type": "object", "required": ["spec"], "properties": { "spec": { "type": "string" } } }, + "result": { "type": "object", "required": ["spec"] } + }, + "targets/list": { + "description": "One row per target mcpp knows: its toolchains, whether one is installed, and the platform that configures it (mcpp 2026-10-28 §9); the host platform when the host graph has one; the last plan of the project.", + "params": { "type": "object", "properties": { "root": { "type": "string" }, "selected": { "type": "string" } } }, + "result": { + "type": "object", + "required": ["host", "selected", "rows"], + "properties": { + "host": { "type": "string" }, + "selected": { "type": "string" }, + "rows": { + "type": "array", + "items": { + "type": "object", + "required": ["target", "toolchains", "platform", "platformText", "selected", "installed"], + "properties": { + "target": { "type": "string" }, + "note": { "type": "string" }, + "pin": { "type": "string" }, + "host": { "type": "boolean" }, + "toolchains": { "type": "array" }, + "platform": { "$ref": "#/$defs/platform" }, + "platformText": { "type": "string" }, + "selected": { "type": "boolean" }, + "installed": { "type": "boolean" } + } + } + }, + "hostPlatform": { "$ref": "#/$defs/platform" }, + "hostPlatformText": { "type": "string" }, + "lastPlan": { "type": "object" } + } + } + }, + "cache/inventory": { "params": { "type": "object", "properties": { "topN": { "type": "integer" } } }, "result": { "type": "object", "required": ["totalBytes", "byKind", "topLabels"] } }, + "cache/plan": { + "description": "What a cleanup would run, how much confirmation it needs, and its preview.", + "params": { "type": "object", "required": ["action"], "properties": { "action": { "type": "string" }, "root": { "type": "string" } } }, + "result": { "type": "object", "required": ["action", "argv", "level"] } + }, + "cache/apply": { + "params": { "type": "object", "required": ["action", "confirmation"], "properties": { "action": { "type": "string" }, "confirmation": { "type": "object" }, "root": { "type": "string" } } }, + "result": { "$ref": "#/$defs/jobRef" } + }, + "graph/packages": { "params": { "$ref": "#/$defs/rooted" }, "result": { "$ref": "#/$defs/graph" } }, + "graph/modules": { "params": { "$ref": "#/$defs/rooted" }, "result": { "$ref": "#/$defs/graph" } }, + "pack/formats": { "params": { "type": "object" }, "result": { "type": ["object", "null"] } }, + "pack/start": { + "description": "A pack job (`mcpp pack --message-format json`): its envelope arrives in job/finished.", + "params": { "type": "object", "required": ["root"], "properties": { "root": { "type": "string" }, "format": { "type": "string" }, "mode": { "type": "string" }, "target": { "type": "string" }, "profile": { "type": "string" } } }, + "result": { "$ref": "#/$defs/jobRef" } + }, + "manifest/check": { + "description": "The manifest's problems as mcpp reports them, located.", + "params": { "$ref": "#/$defs/rooted" }, + "result": { "type": "object", "required": ["root", "diagnostics"], "properties": { "diagnostics": { "type": "array", "items": { "$ref": "#/$defs/diagnostic" } } } } + }, + "toml/complete": { "params": { "$ref": "#/$defs/textPosition" }, "result": { "type": "object", "required": ["items"] } }, + "toml/hover": { "params": { "$ref": "#/$defs/textPosition" }, "result": { "type": ["object", "null"] } }, + "toml/symbols": { "params": { "type": "object", "required": ["text"] }, "result": { "type": "array" } }, + "buildscript/complete": { "params": { "$ref": "#/$defs/textPosition" }, "result": { "type": "object", "required": ["items"] } }, + "shutdown": { "description": "Waits for the requests in flight; the next message is `exit`.", "params": { "type": "object" }, "result": { "type": "null" } }, + "exit": { "description": "A notification: the backend ends (status 0 after shutdown, 1 otherwise).", "params": { "type": "object" }, "result": { "type": "null" } } + }, + "notifications": { + "job/started": { "params": { "type": "object", "required": ["jobId", "kind", "root", "argv"] } }, + "job/output": { "description": "Narration (mcpp's standard error, coloured when the job asked for colour).", "params": { "type": "object", "required": ["jobId", "text"] } }, + "job/plan": { "description": "The configuration a build plans, and the platforms mcpp names for the target and host graphs.", "params": { "type": "object", "required": ["jobId", "root", "configuration"], "properties": { "platform": { "$ref": "#/$defs/platform" }, "hostPlatform": { "$ref": "#/$defs/platform" }, "platformText": { "type": "string" }, "hostPlatformText": { "type": "string" } } } }, + "job/progress": { "params": { "type": "object", "required": ["jobId", "finished", "total"] } }, + "job/diagnostic": { "params": { "allOf": [ { "$ref": "#/$defs/diagnostic" }, { "required": ["jobId", "root"] } ] } }, + "job/artifact": { "params": { "type": "object", "required": ["jobId", "artifact"] } }, + "job/record": { "description": "A record of a job's stream with no meaning the backend names.", "params": { "type": "object", "required": ["jobId", "record"] } }, + "job/finished": { + "params": { + "type": "object", + "required": ["jobId", "status", "exitCode"], + "properties": { + "status": { "enum": ["ok", "failed", "cancelled", "denied", "superseded"] }, + "exitCode": { "type": ["integer", "null"] }, + "durationMs": { "type": "integer" }, + "root": { "type": "string" }, + "kind": { "type": "string" }, + "envelope": { "type": "object" }, + "diagnostics": { "type": "array", "items": { "$ref": "#/$defs/diagnostic" } }, + "artifacts": { "type": "array" } + } + } + }, + "test/result": { + "params": { + "type": "object", + "required": ["jobId", "test", "status"], + "properties": { + "test": { "type": "string" }, + "member": { "type": "string" }, + "status": { "enum": ["passed", "failed", "timedOut", "skipped", "errored"] }, + "durationMs": { "type": "integer" }, + "output": { "type": "string" }, + "reason": { "type": "string" } + } + } + }, + "test/summary": { "params": { "type": "object", "required": ["jobId", "passed", "failed"] } }, + "result/changed": { "description": "A project's result record changed: a build finished, whoever ran it.", "params": { "type": "object", "required": ["root", "result"] } }, + "manifest/changed": { "params": { "type": "object", "required": ["root"] } }, + "manifest/diagnostics": { "params": { "type": "object", "required": ["root", "diagnostics"] } } + }, + "$defs": { + "settingValues": { "type": "object", "additionalProperties": true }, + "resolvedSettings": { "type": "object", "required": ["values", "rejected", "renames", "deprecated"] }, + "rooted": { "type": "object", "required": ["root"], "properties": { "root": { "type": "string" } } }, + "jobRef": { "type": "object", "required": ["jobId"], "properties": { "jobId": { "type": "string" } } }, + "check": { "type": "object", "required": ["id", "status", "message"], "properties": { "status": { "enum": ["ok", "info", "warning", "error"] } } }, + "project": { "type": "object", "required": ["root", "workspaceRoot", "name", "isWorkspaceRoot"] }, + "platform": { "type": ["object", "null"], "properties": { "name": { "type": "string" }, "version": { "type": ["string", "null"] }, "source": { "type": "string" }, "fields": { "type": "object" } } }, + "languageService": { + "type": "object", + "required": ["state", "required", "message", "actions"], + "properties": { + "state": { "enum": ["ok", "outdated", "missing", "unreadable"] }, + "program": { "type": "string" }, + "source": { "type": "string" }, + "version": { "type": "string" }, + "required": { "type": "string" }, + "message": { "type": "string" }, + "actions": { "type": "array", "items": { "type": "object", "required": ["id", "title"], "properties": { "id": { "enum": ["install", "update"] } } } } + } + }, + "command": { + "type": "object", + "required": ["id", "title", "action"], + "properties": { + "id": { "type": "string" }, + "title": { "type": "string" }, + "group": { "type": "string" }, + "groupTitle": { "type": "string" }, + "when": { "type": "string" }, + "quickMenu": { "type": "boolean" }, + "action": { "type": "object", "required": ["kind"], "properties": { "kind": { "enum": ["job", "run", "debug", "cache", "panel", "cancel", "selectTarget", "installToolchain", "selectDefaultToolchain", "newProject", "quickMenu", "selfCheck", "rpc", "languageService", "forward", "editor"] } } } + } + }, + "launchParams": { "type": "object", "required": ["root"], "properties": { "root": { "type": "string" }, "target": { "type": "string" }, "profile": { "type": "string" }, "bin": { "type": "string" }, "args": { "type": "array", "items": { "type": "string" } } } }, + "textPosition": { "type": "object", "required": ["text", "line", "character"], "properties": { "text": { "type": "string" }, "line": { "type": "integer" }, "character": { "type": "integer" } } }, + "graph": { "type": "object", "required": ["nodes", "edges"], "properties": { "nodes": { "type": "array" }, "edges": { "type": "array" } } }, + "diagnostic": { + "type": "object", + "required": ["severity", "message"], + "properties": { "severity": { "type": "string" }, "message": { "type": "string" }, "code": { "type": "string" }, "path": { "type": "string" }, "range": { "type": "object" }, "source": { "type": "string" } } + } + } +} diff --git a/spec/commands.json b/spec/commands.json new file mode 100644 index 0000000..f8bfb44 --- /dev/null +++ b/spec/commands.json @@ -0,0 +1,100 @@ +{ + "version": 1, + "groups": [ + { "id": "project", "title": "group.project" }, + { "id": "cache", "title": "group.cache" }, + { "id": "library", "title": "group.library" }, + { "id": "toolchain", "title": "group.toolchain" }, + { "id": "languageService", "title": "group.languageService" }, + { "id": "tools", "title": "group.tools" } + ], + "commands": [ + { "id": "mcpp.build", "group": "project", "icon": { "vscode": "$(tools)", "jetbrains": "AllIcons.Actions.Compile" }, + "when": "mcpp.inProject", "keybinding": { "key": "ctrl+alt+b", "mac": "cmd+alt+b" }, + "action": { "kind": "job", "job": "build" }, "quickMenu": true }, + { "id": "mcpp.run", "group": "project", "icon": { "vscode": "$(play)", "jetbrains": "AllIcons.Actions.Execute" }, + "when": "mcpp.inProject", "keybinding": { "key": "ctrl+alt+r", "mac": "cmd+alt+r" }, + "menus": [ { "menu": "editor/title", "group": "navigation@1", "when": "mcpp.inProject && mcpp.editorTitleButtons" } ], + "action": { "kind": "run" }, "quickMenu": true }, + { "id": "mcpp.debug", "group": "project", "icon": { "vscode": "$(debug-alt)", "jetbrains": "AllIcons.Actions.StartDebugger" }, + "when": "mcpp.inProject", "action": { "kind": "debug" }, "quickMenu": true }, + { "id": "mcpp.test", "group": "project", "icon": { "vscode": "$(beaker)", "jetbrains": "AllIcons.RunConfigurations.TestState.Run" }, + "when": "mcpp.inProject", "keybinding": { "key": "ctrl+alt+t", "mac": "cmd+alt+t" }, + "menus": [ { "menu": "editor/title", "group": "navigation@2", "when": "mcpp.inProject && mcpp.editorTitleButtons" } ], + "action": { "kind": "job", "job": "test" }, "quickMenu": true }, + { "id": "mcpp.clean", "group": "project", "icon": { "jetbrains": "AllIcons.Actions.GC" }, + "when": "mcpp.inProject", "action": { "kind": "cache", "plan": "project" }, "quickMenu": true }, + { "id": "mcpp.pack", "group": "project", "icon": { "vscode": "$(package)", "jetbrains": "AllIcons.Nodes.PpLib" }, + "when": "mcpp.inProject", "action": { "kind": "panel", "panel": "pack" }, "quickMenu": true }, + { "id": "mcpp.cancelJob", "group": "project", "icon": { "vscode": "$(debug-stop)", "jetbrains": "AllIcons.Actions.Suspend" }, + "when": "mcpp.jobRunning", "action": { "kind": "cancel" } }, + { "id": "mcpp.selectTarget", "group": "toolchain", "icon": { "vscode": "$(target)", "jetbrains": "AllIcons.General.Gear" }, + "action": { "kind": "selectTarget" }, "quickMenu": true }, + { "id": "mcpp.showTargets", "group": "toolchain", "icon": { "vscode": "$(server-environment)", "jetbrains": "AllIcons.Nodes.Deploy" }, + "action": { "kind": "panel", "panel": "targets" }, "quickMenu": true }, + { "id": "mcpp.showToolchains", "group": "toolchain", "action": { "kind": "panel", "panel": "targets" } }, + { "id": "mcpp.installToolchain", "group": "toolchain", "action": { "kind": "installToolchain" } }, + { "id": "mcpp.selectDefaultToolchain", "group": "toolchain", "action": { "kind": "selectDefaultToolchain" } }, + { "id": "mcpp.newProject", "group": "project", "icon": { "vscode": "$(new-folder)", "jetbrains": "AllIcons.Actions.NewFolder" }, + "action": { "kind": "newProject" }, "quickMenu": true }, + { "id": "mcpp.showMenu", "group": "tools", "icon": { "vscode": "$(list-flat)" }, + "when": "mcpp.inProject", "keybinding": { "key": "ctrl+alt+m", "mac": "cmd+alt+m" }, + "action": { "kind": "quickMenu" }, "editors": [ "vscode" ] }, + { "id": "mcpp.openSettings", "group": "tools", "icon": { "vscode": "$(settings-gear)", "jetbrains": "AllIcons.General.Settings" }, + "action": { "kind": "panel", "panel": "settings" }, "quickMenu": true }, + { "id": "mcpp.selfCheck", "group": "tools", "icon": { "jetbrains": "AllIcons.Actions.Checked" }, + "action": { "kind": "selfCheck" }, "quickMenu": true }, + { "id": "mcpp.autoConfigureModules", "group": "languageService", "action": { "kind": "job", "job": "build", "then": "languageService" } }, + { "id": "mcpp.refreshCompilationDatabase", "group": "languageService", "action": { "kind": "job", "job": "build" } }, + + { "id": "mcpp.refreshCacheStats", "group": "cache", "icon": { "vscode": "$(refresh)", "jetbrains": "AllIcons.Actions.Refresh" }, + "menus": [ { "menu": "view/title", "group": "navigation@2", "when": "view == mcpp.cache" } ], + "action": { "kind": "panel", "panel": "cache", "refresh": true } }, + { "id": "mcpp.showCachePanel", "group": "cache", "action": { "kind": "panel", "panel": "cache" }, "quickMenu": true }, + { "id": "mcpp.showCacheEntry", "group": "cache", "palette": false, "action": { "kind": "panel", "panel": "cache" } }, + { "id": "mcpp.cleanStaleArtifacts", "group": "cache", "action": { "kind": "cache", "plan": "stale" } }, + { "id": "mcpp.cleanProjectArtifacts", "group": "cache", "when": "mcpp.inProject", + "keybinding": { "key": "ctrl+alt+l", "mac": "cmd+alt+l" }, "action": { "kind": "cache", "plan": "project" } }, + { "id": "mcpp.gcGlobalCache", "group": "cache", "action": { "kind": "cache", "plan": "cacheGc" } }, + { "id": "mcpp.pruneGlobalCache", "group": "cache", "action": { "kind": "cache", "plan": "cachePrune" } }, + { "id": "mcpp.verifyGlobalCache", "group": "cache", "action": { "kind": "cache", "plan": "cacheVerify" } }, + { "id": "mcpp.cleanLegacyCache", "group": "cache", "action": { "kind": "cache", "plan": "cacheLegacy" } }, + + { "id": "mcpp.library.search", "group": "library", "icon": { "vscode": "$(cloud-download)", "jetbrains": "AllIcons.Actions.Find" }, + "action": { "kind": "panel", "panel": "libraries" }, "quickMenu": true }, + { "id": "mcpp.library.openDetail", "group": "library", "palette": false, "action": { "kind": "panel", "panel": "library" } }, + { "id": "mcpp.library.updateIndex", "group": "library", "icon": { "vscode": "$(cloud-download)", "jetbrains": "AllIcons.Actions.Download" }, + "menus": [ { "menu": "view/title", "group": "navigation@2", "when": "view == mcpp.library" } ], + "action": { "kind": "rpc", "method": "library/updateIndex" } }, + { "id": "mcpp.project.showDependencyGraph", "group": "project", "icon": { "vscode": "$(type-hierarchy)", "jetbrains": "AllIcons.Graph.Layout" }, + "menus": [ { "menu": "view/item/context", "group": "inline@1", "when": "view == mcpp.project && viewItem == mcppProjectDependencies" } ], + "action": { "kind": "panel", "panel": "graph", "graph": "packages" }, "quickMenu": true }, + { "id": "mcpp.project.showModuleDependencyGraph", "group": "project", + "action": { "kind": "panel", "panel": "graph", "graph": "modules" }, "quickMenu": true }, + + { "id": "mcpp.languageServer.refreshState", "group": "languageService", "action": { "kind": "languageService" } }, + { "id": "mcpp.openMcpplsSettings", "group": "languageService", "palette": false, "editors": [ "vscode" ], + "action": { "kind": "editor", "vscode": "workbench.action.openSettings", "args": [ "@ext:sunrisepeak.mcpp-language-server" ] } }, + { "id": "mcpp.languageServer.restart", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.restartServer" ] } }, + { "id": "mcpp.languageServer.restartEngine", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.restartClangd" ] } }, + { "id": "mcpp.languageServer.resetWorkspaceCache", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.resetWorkspaceCache" ] } }, + { "id": "mcpp.languageServer.selectContext", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.selectContext" ] } }, + { "id": "mcpp.languageServer.showModuleGraph", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.showModuleGraph" ] } }, + { "id": "mcpp.languageServer.showLogs", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.showLogs" ] } }, + { "id": "mcpp.languageServer.collectReport", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.collectReport" ] } }, + { "id": "mcpp.languageServer.exportDiagnosticBundle", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.exportDiagnosticBundle" ] } }, + { "id": "mcpp.languageServer.revealBundle", "group": "languageService", "palette": false, "action": { "kind": "forward", "commands": [ "mcppls.revealCacheDirectory" ] } }, + { "id": "mcpp.languageServer.openLogFolder", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.revealCacheDirectory" ] } }, + { "id": "mcpp.languageServer.runBuildToolInTerminal", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.runBuildToolInTerminal" ] } }, + { "id": "mcpp.languageServer.manageConflicts", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.turnOffOtherCppFeatures" ] } }, + { "id": "mcpp.languageServer.restoreConflicts", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.restoreOtherCppFeatures" ] } }, + { "id": "mcpp.languageServer.toggleInWorkspace", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.turnOffInWorkspace", "mcppls.turnOnInWorkspace" ] } }, + { "id": "mcpp.languageServer.installTools", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.installCommandLineTools" ] } }, + { "id": "mcpp.languageServer.reviewChanges", "group": "languageService", "action": { "kind": "forward", "commands": [ "mcppls.review.run" ] } }, + { "id": "mcpp.configureLanguageServer", "group": "languageService", "deprecated": true, "action": { "kind": "forward", "commands": [ "mcppls.selectContext" ] } }, + { "id": "mcpp.configureClangd", "group": "languageService", "deprecated": true, "action": { "kind": "forward", "commands": [ "mcppls.selectContext" ] } }, + { "id": "mcpp.checkModuleSupport", "group": "languageService", "deprecated": true, "action": { "kind": "forward", "commands": [ "mcppls.restartServer" ] } }, + { "id": "mcpp.showModuleGraph", "group": "languageService", "deprecated": true, "action": { "kind": "forward", "commands": [ "mcppls.showModuleGraph" ] } }, + { "id": "mcpp.showLanguageServerLogs", "group": "languageService", "deprecated": true, "action": { "kind": "forward", "commands": [ "mcppls.showLogs" ] } } + ] +} diff --git a/spec/i18n/manifest.en.json b/spec/i18n/manifest.en.json index d1aab1b..25e9348 100644 --- a/spec/i18n/manifest.en.json +++ b/spec/i18n/manifest.en.json @@ -206,5 +206,39 @@ "viewsContainer.mcpp.title": "mcpp", "viewsWelcome.library": "No mcpp package index was found on this machine.\n\nRun `mcpp index update` once, or set `mcpp.library.indexPath` to an index checkout.\n[Run mcpp index update](command:mcpp.library.updateIndex)", "command.mcpp.project.showDependencyGraph.title": "Show Project Dependency Graph", - "command.mcpp.project.showModuleDependencyGraph.title": "Show C++ Modules Dependency Graph" + "command.mcpp.project.showModuleDependencyGraph.title": "Show C++ Modules Dependency Graph", + "command.mcpp.debug.title": "Debug", + "command.mcpp.pack.title": "Pack", + "command.mcpp.cancelJob.title": "Cancel the Running Job", + "command.mcpp.selectTarget.title": "Select the Build Target", + "command.mcpp.showTargets.title": "Targets and Platforms", + "group.project": "Project", + "group.cache": "Cache", + "group.library": "Libraries", + "group.toolchain": "Targets and Toolchains", + "group.languageService": "C++ Modules Language Service", + "group.tools": "Tools", + "view.mcpp.targets.name": "Targets", + "debugger.mcpp.label": "mcpp", + "taskDefinition.mcpp.command": "The mcpp command: build, test, run or clean.", + "taskDefinition.mcpp.target": "The target to build for; empty for this machine.", + "taskDefinition.mcpp.profile": "The build profile: dev or release.", + "taskDefinition.mcpp.args": "Extra arguments passed to mcpp.", + "taskDefinition.mcpp.root": "The project's directory; empty for the current project.", + "debug.mcpp.target": "The target to debug; empty for this machine.", + "debug.mcpp.profile": "The build profile: dev or release.", + "debug.mcpp.engine": "The debugger: auto, cppdbg, lldb, lldb-dap or gdb.", + "debug.mcpp.args": "Arguments passed to the program.", + "mcpp.ide.backendPath.title": "Set the mcpp-ide backend path", + "mcpp.ide.backendPath.description": "The mcpp-ide program the extension starts. Empty: the backend shipped with the extension, then the one xlings installed, then PATH.", + "mcpp.build.onSave.title": "Build when a file is saved", + "mcpp.build.onSave.description": "Start a build of the file's project when a source or mcpp.toml is saved. A save while a build waits replaces it; a running build is cancelled and started again.", + "mcpp.build.profile.title": "Choose the build profile", + "mcpp.build.profile.description": "The profile build, run, test and debug use: dev (unoptimised, debug information) or release.", + "mcpp.build.target.title": "Choose the build target", + "mcpp.build.target.description": "The target build, run, test, debug and pack use, as mcpp names it (x86_64-linux-musl, x86_64-openkal). Empty: this machine. The Targets panel lists the targets and the platform that configures each.", + "mcpp.trust.denyEffects.title": "Effects denied in an untrusted workspace", + "mcpp.trust.denyEffects.description": "What mcpp may not do while the workspace is not trusted (mcpp --deny): a run that needs one of them stops before it and says so. Trusting the workspace lifts the list.", + "mcpp.debug.engine.title": "Choose the debugger", + "mcpp.debug.engine.description": "The debug adapter a debug session uses. auto: CodeLLDB when it is installed, then the C/C++ extension's gdb or lldb, then lldb-dap." } diff --git a/spec/i18n/manifest.zh-cn.json b/spec/i18n/manifest.zh-cn.json index 8f6daf9..7417493 100644 --- a/spec/i18n/manifest.zh-cn.json +++ b/spec/i18n/manifest.zh-cn.json @@ -206,5 +206,39 @@ "viewsContainer.mcpp.title": "mcpp", "viewsWelcome.library": "本机没有找到 mcpp 包索引。\n\n先运行一次 `mcpp index update`,或用 `mcpp.library.indexPath` 指向一个索引检出。\n[运行 mcpp index update](command:mcpp.library.updateIndex)", "command.mcpp.project.showDependencyGraph.title": "显示项目依赖图", - "command.mcpp.project.showModuleDependencyGraph.title": "显示 C++ Modules 依赖图" + "command.mcpp.project.showModuleDependencyGraph.title": "显示 C++ Modules 依赖图", + "command.mcpp.debug.title": "调试", + "command.mcpp.pack.title": "打包", + "command.mcpp.cancelJob.title": "取消正在运行的任务", + "command.mcpp.selectTarget.title": "选择构建目标", + "command.mcpp.showTargets.title": "目标与平台", + "group.project": "工程", + "group.cache": "缓存", + "group.library": "库", + "group.toolchain": "目标与工具链", + "group.languageService": "C++ 模块语言服务", + "group.tools": "工具", + "view.mcpp.targets.name": "目标", + "debugger.mcpp.label": "mcpp", + "taskDefinition.mcpp.command": "mcpp 命令:build、test、run 或 clean。", + "taskDefinition.mcpp.target": "构建目标;留空表示本机。", + "taskDefinition.mcpp.profile": "构建配置:dev 或 release。", + "taskDefinition.mcpp.args": "传给 mcpp 的额外参数。", + "taskDefinition.mcpp.root": "工程目录;留空表示当前工程。", + "debug.mcpp.target": "要调试的目标;留空表示本机。", + "debug.mcpp.profile": "构建配置:dev 或 release。", + "debug.mcpp.engine": "调试器:auto、cppdbg、lldb、lldb-dap 或 gdb。", + "debug.mcpp.args": "传给程序的参数。", + "mcpp.ide.backendPath.title": "设置 mcpp-ide 后端路径", + "mcpp.ide.backendPath.description": "扩展启动的 mcpp-ide 程序。留空:先用扩展自带的后端,再用 xlings 安装的,最后用 PATH 中的。", + "mcpp.build.onSave.title": "保存时构建", + "mcpp.build.onSave.description": "保存源文件或 mcpp.toml 时构建其所在工程。构建在等待时再次保存会替换它;正在运行的构建会被取消并重新开始。", + "mcpp.build.profile.title": "选择构建配置", + "mcpp.build.profile.description": "构建、运行、测试与调试使用的配置:dev(不优化,带调试信息)或 release。", + "mcpp.build.target.title": "选择构建目标", + "mcpp.build.target.description": "构建、运行、测试、调试与打包使用的目标,按 mcpp 的命名(x86_64-linux-musl、x86_64-openkal)。留空:本机。目标面板列出各目标及配置它的平台。", + "mcpp.trust.denyEffects.title": "未受信任工作区禁止的副作用", + "mcpp.trust.denyEffects.description": "工作区未受信任时 mcpp 不得做的事(mcpp --deny):需要其中之一的运行会在发生前停止并说明原因。信任工作区后解除。", + "mcpp.debug.engine.title": "选择调试器", + "mcpp.debug.engine.description": "调试会话使用的调试适配器。auto:已安装 CodeLLDB 时用它,其次用 C/C++ 扩展的 gdb 或 lldb,再次用 lldb-dap。" } diff --git a/spec/i18n/runtime.zh-cn.json b/spec/i18n/runtime.zh-cn.json index fe18bbb..0d2c85a 100644 --- a/spec/i18n/runtime.zh-cn.json +++ b/spec/i18n/runtime.zh-cn.json @@ -5,34 +5,46 @@ "About {0} would be freed ({1} entries).": "预计释放约 {0}({1} 个条目)。", "Accepts family, family@version, namespace, partial versions and mcpp's compatible legacy spellings": "支持 family、family@version、namespace、部分版本和 mcpp 兼容旧拼写", "Actions": "操作", + "Add dependency": "添加依赖", + "Add development dependency": "添加开发依赖", "Add to mcpp.toml": "添加到 mcpp.toml", "Added": "已添加", "Added {0} to mcpp.toml.": "已把 {0} 加入 mcpp.toml。", + "Adding dependency…": "正在添加依赖…", "Adding {0}…": "正在添加 {0}…", "Age distribution": "按最近使用时间分布", "All": "全部", "Already added": "已添加", + "Already declared": "已声明", "Already within {0} GiB.": "当前已在 {0} GiB 以内。", "Also empty the shared build cache": "同时清空共享构建缓存", "An mcpp operation is already running.": "已有 mcpp 操作正在运行。", "An mcpp operation is already running; not starting {0} now.": "已有 mcpp 操作正在运行,暂不启动 {0}。", "An mcpp operation is already running; wait for it to finish and try again.": "已有 mcpp 操作正在运行,请等待完成后再试。", "Array shorthand: implies the feature only": "数组简写:仅隐含 feature", + "Back": "后退", + "Back to project": "返回项目", "Back to the toolchain installation flow": "回到工具链安装流程", "Basics": "基本信息", + "Bring it into your code": "在代码里引入", + "Browse libraries; select an mcpp project in the detail page to add dependencies.": "可以浏览库;请在详情页选择 mcpp 项目后添加依赖。", "Budget simulator": "预算模拟器", "Build": "构建", "Build and refresh the language service": "构建并刷新语言服务", "Build cache": "构建缓存", "Build configuration": "构建配置", + "Build dependencies are used by the build script. Copy this entry into mcpp.toml; mcpp add does not support this group yet.": "构建依赖供构建脚本使用;当前 mcpp add 尚不支持此分组,请复制此项并编辑 mcpp.toml。", + "Build dependency": "构建依赖", "Build environment (supplied by xlings)": "构建环境(xlings 供给)", "Build profiles": "构建档案", "Build shape": "构建形态", "Build targets": "构建目标", "Build the current mcpp project and refresh the C++ Modules language service?": "是否构建当前 mcpp 工程并刷新 C++ 模块语言服务?", "Build-time dependencies (pulled at build time only, invisible at run time)": "构建期依赖(仅构建期拉取,运行时不可见)", + "Bundled official index tests · commit {0}": "插件内置官方索引测试 · 提交 {0}", "Bytes and entries by how long ago they were last used.": "按最近使用时间统计的字节数与条目数。", "C++ Modules (provided by the mcpp language server extension): {0}": "C++ Modules(由 mcpp 语言服务扩展提供):{0}", + "C++ Modules Deps": "C++ Modules 依赖图", "C++ Modules command failed: {0}": "C++ Modules 命令失败:{0}", "C++ Modules is not installed": "未安装 C++ Modules", "C++ Modules language service": "C++ Modules 语言服务", @@ -57,11 +69,16 @@ "Capture logs now": "现在抓取", "Caret constraint (^) by default; ~, = and range combinations such as \">=1.0, <2.0\" are also supported.": "默认 caret 约束(^);也支持 ~、= 与 \">=1.0, <2.0\" 范围组合。", "Changed from the default": "已偏离默认值", + "Changing dependency groups is not supported here. Edit mcpp.toml to move the declaration.": "此处暂不支持迁移依赖分组,请编辑 mcpp.toml 移动声明。", + "Changing this declaration requires a manifest edit. Copy the entry and update its dependency group in mcpp.toml.": "请复制声明并在 mcpp.toml 中调整依赖分组;已有声明不会自动迁移。", "China mirror": "国内镜像", "Choose a global default": "选择全局默认", + "Choose a module source file": "选择模块源码文件", "Choose a project, toolchain, cache or C++ Modules action": "选择工程、工具链、缓存或 C++ Modules 操作", + "Choose project": "选择项目", "Choose the mcpp global default toolchain": "选择 mcpp 全局默认工具链", "Choose the project location (2/2)": "选择项目位置(2/2)", + "Choose the target mcpp project": "选择目标 mcpp 项目", "Choosing here only changes the mcpp global configuration; it does not build the project": "选择后只修改 mcpp 全局配置,不会自动构建工程", "Clean": "清理", "Clean and build": "清理并构建", @@ -69,9 +86,13 @@ "Clean project artifacts": "清理项目产物", "Clean stale artifacts": "清理过期产物", "Clean target": "清理 target", + "Clear search": "清空搜索", "Click a version to aim the command above at it.": "点一个版本,上面的命令就会指向它。", + "Collapse": "收起", + "Collapse importers": "折叠父节点", "Collect a diagnostic report": "收集诊断报告", "Collect the global cache to a budget": "将全局缓存收敛到预算内", + "Collect the shared build cache to a budget?": "将共享构建缓存收敛到预算?", "Collect to this budget": "收敛到此预算", "Command": "命令", "Common commands": "常用命令", @@ -83,27 +104,59 @@ "Confirm a cleanup this large": "确认如此规模的清理", "Confirm once more": "请再次确认", "Confirm one-click setup": "确认一键配置", + "Copied": "已复制", + "Copied to the clipboard.": "已复制到剪贴板。", + "Copy": "复制", + "Copy Mermaid": "复制 Mermaid", + "Copy failed": "复制失败", + "Copying…": "复制中…", + "Could not add the dependency. See output for details.": "无法添加依赖,请查看输出了解详情。", + "Could not export this graph. Try SVG or a smaller view.": "无法导出此图,请尝试 SVG 或更小的视图。", + "Could not open the browser or copy the link: {0}": "无法打开浏览器或复制链接:{0}", + "Could not open the browser. Link copied to clipboard.": "无法打开浏览器,链接已复制到剪贴板。", + "Could not read package details. See output for details.": "无法读取包详情,请查看输出了解详情。", + "Could not read project dependencies: {0}": "无法读取项目依赖:{0}", + "Could not read the index: {0}": "无法读取索引:{0}", + "Could not render the graph. Copy Mermaid source or refresh to retry.": "依赖图渲染失败,可复制 Mermaid 源码或刷新重试。", + "Could not write the clipboard.": "无法写入剪贴板。", "Create and open": "创建并打开", "Create the project here": "在此创建项目", "Current effective toolchain": "当前有效工具链", "Current mcpp project": "当前 mcpp 工程", "Currently effective item": "当前有效项", + "Custom index": "自定义索引", "Data source": "数据来源", + "Declaration graph · dashed edges are conditional · lockfile supplies versions": "声明关系图 · 虚线为条件依赖 · 锁文件提供版本", "Declare dependency versions centrally; members inherit them with workspace = true": "集中声明依赖版本,成员用 workspace = true 继承", + "Declared": "已声明", "Declared in mcpp.toml; the resolved version comes from mcpp.lock.": "声明来自 mcpp.toml,解析值来自 mcpp.lock。", "Default": "默认", "Degraded": "降级", "Delete the target/ directory of this project: {0}/target": "将删除当前工程的 target 目录:{0}/target", "Dependencies": "依赖", "Dependencies ({0})": "依赖 ({0})", + "Dependencies depth": "依赖深度", + "Dependencies unavailable — click to retry": "暂时无法读取依赖,点击重试", + "Dependencies will be added to this project's mcpp.toml": "依赖将添加到此项目的 mcpp.toml", + "Dependency graph": "依赖图", + "Dependency type": "依赖类型", "Deprecated": "已弃用", + "Depth": "深度", "Descriptor not readable": "描述符无法读取", + "Descriptor-level dependencies; the selected version may differ. Resolved values refer to this project's lockfile.": "这里展示包描述中的依赖,所选版本的依赖可能不同;解析版本来自当前项目的锁文件。", "Details": "详情", "Detect": "检测", + "Development dependency": "开发依赖", "Development/test dependencies": "开发/测试依赖", "Direction: disable.": "方向:停用。", "Direction: enable.": "方向:启用。", + "Directories written in the last {0} day(s) are kept. mcpp decides which ones are stale; the preview above is its own list.": "保留最近 {0} 天内写入的目录。哪些目录已过期由 mcpp 判定;上方预览就是它给出的列表。", + "Drop cache entries that have not been used for a while?": "删除一段时间未使用的缓存条目?", "Drop entries unused for a while": "按时间丢弃长期未用的条目", + "Drop every package entry from the shared cache?": "删除共享缓存中的全部包条目?", + "Drop every standard library module entry from the shared cache?": "删除共享缓存中的全部标准库模块条目?", + "Drop the entire shared build cache?": "删除整个共享构建缓存?", + "Edges come from manifests and local index descriptors; lockfile versions are shown when available. This is a declaration graph, not a resolved build graph. Dashed nodes have no local dependency metadata; conditional edges may not apply to this environment.": "关系来自项目清单和本地索引描述符;有锁定版本时显示锁定版本。这是声明关系图,不代表实际构建解析结果。虚线节点缺少本地依赖元数据,条件关系可能不适用于当前环境。", "Effective target: host (mcpp shows no explicit target)": "有效 target:host(mcpp 未显示显式 target)", "Effective target: {0}": "有效 target:{0}", "Effective toolchain of this project": "当前工程有效工具链", @@ -112,21 +165,36 @@ "Enter a toolchain spec": "输入工具链 spec", "Enter a whole number of GiB": "请输入整数 GiB", "Entries": "条目", + "Entries unused for longer than {0} day(s) are removed. Projects that used one rebuild it.": "超过 {0} 天未使用的条目会被删除。用到它的工程会重新构建。", + "Entry group": "入口分组", + "Environment platform": "当前环境平台", "Environment self-check": "环境自检", "Estimated size": "估算大小", "Every entry matches its manifest.": "每个条目都与它的清单一致。", "Every figure here is read from mcpp cache list, mcpp cache dir and a bounded walk of target/. Sizes are estimates; cleanup runs only after confirmation and never automatically.": "这里的数字来自 mcpp cache list、mcpp cache dir 以及对 target/ 的有界遍历。体积是估算值;清理只在确认后执行,绝不自动进行。", + "Every mcpp project on this machine re-prepares the standard library module afterwards. Package entries are kept.": "此后本机所有 mcpp 工程都会重新准备标准库模块。包条目保留。", + "Every mcpp project on this machine rebuilds its dependencies afterwards. Standard library module entries are kept.": "此后本机所有 mcpp 工程都会重新构建依赖。标准库模块条目保留。", "Example code": "示例代码", "Example project: {0} — built and run by the index's CI, not written for this page.": "示例工程:{0} —— 由索引的 CI 实际构建并运行过,不是为这个页面写的。", "Exit code {0}": "退出码 {0}", + "Expand importers": "展开父节点", + "Expand next level": "展开下一层", "Explain this code with: {0}": "解释此退出码:{0}", + "Export": "导出", + "Export PNG": "导出 PNG", + "Export SVG": "导出 SVG", "Export a diagnostic bundle": "导出诊断包", "Failed with exit code {0}": "失败,退出码 {0}", "Feature definitions": "feature 定义", "Filters": "筛选", + "Find a node…": "查找节点…", "Fine-tuning of the vendored filtering policy": "vendored 过滤策略微调", + "Fit": "适应窗口", + "Focus": "聚焦", + "Focus this result": "以此结果为焦点", "For example gcc, llvm@20.1.7, xim:gcc@16, msvc, mingw; mcpp normalises compatible spellings": "例如 gcc、llvm@20.1.7、xim:gcc@16、msvc、mingw;兼容写法由 mcpp 规范化", "From the global default": "来自全局默认", + "From the index's example source": "来自索引示例源码", "From this project's mcpp.toml, overriding the global default": "来自当前项目 mcpp.toml,覆盖全局默认", "Generated file (relative path → content, part of the fingerprint)": "生成文件(相对路径 → 内容,进指纹)", "Generated files (path → content)": "生成文件(路径 → 内容)", @@ -135,19 +203,24 @@ "Global build cache": "全局构建缓存", "Global default: ": "全局默认:", "Global default: {0}": "全局默认:{0}", + "Graph view": "图视图", "Host runtime capabilities": "主机运行时能力", "Host tool binary overrides": "host 工具二进制覆盖", "Host tools produced by the dependency (must be a bin target of that package)": "依赖产出的 host 工具(须为该包的 bin target)", "I understand this affects every mcpp project on this machine": "我明白这会影响本机所有 mcpp 工程", "I understand this removes entries other mcpp projects may use": "我明白这会删除其它 mcpp 工程可能正在使用的条目", + "Importers depth": "父节点深度", "Include directories": "包含目录", "Incomplete entries": "不完整条目", + "Index update failed; showing the last available local snapshot.": "索引更新失败,继续显示上次可用的本地快照。", + "Index updated; {0} local packages.": "索引已更新,本地共 {0} 个包。", "Index versions mcpp aggregates by family; no host payload is promised": "mcpp 按 family 聚合的索引版本;未承诺 host payload", "Inspect the toolchain": "查看工具链", "Install": "安装", "Install C++ Modules": "安装 C++ Modules", "Install an mcpp toolchain": "安装 mcpp 工具链", "Install extension": "安装扩展", + "Install mcppls": "安装 mcppls", "Install toolchain": "安装工具链", "Installable: {0}": "可安装:{0}", "Installed": "已安装", @@ -156,17 +229,26 @@ "Keep the shared build cache under how many GiB?": "共享构建缓存保留在多少 GiB 以内?", "Label": "包", "Language service": "语言服务", + "Large graph truncated at 120 nodes or 240 edges.": "大型依赖图已截断(最多 120 个节点或 240 条关系)。", "Largest packages": "占用最多的包", "Largest packages (top {0})": "占用最多的包(前 {0})", "Last use": "最近使用", "Legacy compatibility field; new projects should use [package].standard": "旧版兼容字段;新项目请用 [package].standard", + "Legend and source": "图例与源码", + "Libraries": "库", "Library": "库", "Library package {0}": "库包 {0}", "Library root-module convention": "库根模块约定", "License": "许可", + "List the shared build cache": "列出共享构建缓存", + "Locate focus": "定位焦点", + "Locate selected": "定位选中", "Long dep spec: request a feature of that dependency": "长式 dep spec:请求该依赖的 feature", "MSVC detection finished. Choose a global default from the latest list?": "MSVC 检测完成。是否从最新列表中选择全局默认?", + "Main": "主程序", "Manifest reference": "清单参考", + "Maximum dependency depth: 3": "最多展示 3 层依赖", + "Mermaid source": "Mermaid 源码", "Metadata and assets compiled into the product (PE targets only)": "编译进产物的元数据与资产(仅 PE 目标)", "Module graph": "模块图", "More ({0})…": "其它 {0} 项…", @@ -176,6 +258,7 @@ "New mcpp project…": "新建 mcpp 工程…", "New project": "新建工程", "Newest use: {0}": "最近使用:{0}", + "Next entries": "下一批入口", "No cache entries were found.": "没有找到缓存条目。", "No cache label was read.": "没有读到缓存标签。", "No descriptor was read.": "没有读到任何描述符。", @@ -184,84 +267,134 @@ "No further packages were found in the other registries.": "其它 registry 中没有找到更多包。", "No installed toolchain is usable for the host target, so a global default cannot be set here. For target-specific toolchains use the mcpp CLI; on Windows install Visual Studio first.": "没有可用于 host target 的已安装工具链,不能在此处设置全局默认。target 专用工具链请使用 mcpp CLI;Windows MSVC 请先安装 Visual Studio。", "No local index was read.": "没有读取本地索引。", + "No local mcpp-index found": "未找到本地 mcpp-index", "No mcpp index was found. Run mcpp: Refresh the mcpp Package Index once, or set mcpp.library.indexPath to an index checkout.": "没有找到 mcpp 索引。先执行一次 mcpp: 刷新 mcpp 包索引,或用 mcpp.library.indexPath 指向一个索引检出。", "No mcpp project in this workspace": "当前工作区没有 mcpp 工程", "No mcpp.toml was found in this workspace. Run this command inside an mcpp project.": "当前工作区没有找到 mcpp.toml。请在 mcpp 工程中执行此命令。", + "No module relationships were found for this project.": "此项目尚无模块关系。", + "No other C++ language service (C/C++, clangd, ccls) is active, so no result is shown twice.": "没有其他 C++ 语言服务(C/C++、clangd、ccls)在工作,结果不会重复出现。", "No package matches this search.": "没有匹配的包。", "No settings match the search": "没有匹配的设置", "No target is selected; for a target-specific install use the mcpp CLI": "不选择 target;target 专用安装请使用 mcpp CLI", "No target/ directory": "没有 target/ 目录", + "No verified import or header path is available locally. See the repository or index site for usage.": "本地没有可验证的模块名或头文件路径,请查看仓库或索引站的用法说明。", + "No version is published for the current environment platform.": "当前环境平台没有可用的发布版本。", "No workspace folder is open": "未打开工作区文件夹", + "Node actions": "节点操作", "Not measured yet": "尚未测量", "Off by default: this tier runs mcpp search, which may use the network and is read from human output on a best-effort basis. Failures fall back to the local index.": "默认关闭:这一档会调用 mcpp search,可能联网,且只能从人类输出尽力解析。失败时退回本地索引。", + "Official index": "官方索引", "Oldest use": "最早使用", "Oldest use: {0}": "最早使用:{0}", "One value per line": "每行一个值", + "Only C++ Modules is serving C++": "仅 C++ Modules 在提供 C++ 语言服务", "Only modified": "仅显示已修改", + "Only the directory older mcpp releases wrote is removed; the current cache is kept.": "只删除旧版 mcpp 写入的目录;当前缓存保留。", + "Open an mcpp project first.": "请先打开一个 mcpp 项目。", "Open in the Settings editor": "在设置编辑器中打开", "Open logs": "打开日志", + "Open mcpp.toml": "打开 mcpp.toml", "Open on the index site": "在索引站打开", + "Open read-only source": "打开只读源码", + "Open source": "打开源码", + "Open source file": "打开源文件", "Open the C++ Modules settings": "打开 C++ Modules 设置", "Open the detail page for {0}": "打开 {0} 的详情页", "Open the mcpp project and toolchain quick menu": "打开 mcpp 项目和工具链快捷菜单", "Open the repository": "打开仓库", + "Opened in your browser.": "已在浏览器中打开。", "Opened {0} in your browser.": "已在浏览器中打开 {0}。", "Opening {0}…": "正在打开 {0}…", "Optional dependencies pulled in by a feature": "由 feature 拉取的可选依赖", + "Other": "其他", + "Other C++ language services": "其他 C++ 语言服务", + "Other platforms (read only)": "其它平台(只读)", + "Other registries": "其它 registry", + "Other registry": "其它 registry", "Override a host tool with an existing binary (skips the build)": "用已有二进制覆盖 host 工具(跳过构建)", "POSIX environment": "POSIX 环境", + "Package and standard library entries go. Every mcpp project on this machine rebuilds from scratch afterwards.": "包与标准库条目都会被删除。此后本机所有 mcpp 工程都从头构建。", "Package metadata": "包元数据", + "Packages": "包依赖", + "Packages show declarations; modules show mcppls imports. External modules stop after one hop.": "包图显示声明关系;模块图来自 mcppls,外部模块只显示一层。", "Path dependency (local development)": "路径依赖(本地开发)", "Path: {0}": "路径:{0}", "Pin the xlings tool version": "固定 xlings 工具版本", "Pin tool versions": "固定工具版本", + "Platforms and versions": "平台与版本", "Pre-v1 cache": "pre-v1 遗留缓存", "Presets": "预设", + "Previous entries": "上一批入口", + "Project": "项目", "Project artifacts": "工程产物", "Project artifacts are not available.": "工程产物不可用。", "Project artifacts could not be measured.": "无法测量工程产物。", "Project cache": "项目缓存", + "Project dependency": "项目依赖", + "Project dependency graph": "项目依赖图", "Project-level index redirection": "项目级索引重定向", "Provided by": "提供方", "Read offline from {0} in the {1} index ({2} index folder(s) found).": "已从 {1} 索引离线读取 {0}(共找到 {2} 个索引目录)。", "Read-only view of what mcpp currently resolves": "只读查看 mcpp 当前解析结果", + "Read-only.": "只读。", + "Read-only: every entry is checked against its recorded contents.": "只读:逐条按记录的内容校验。", + "Reading dependencies…": "正在读取依赖…", + "Reading package details…": "正在读取包详情…", + "Reading project dependencies…": "正在读取项目依赖…", "Reading the index…": "正在读取索引…", "Reading {0}…": "正在读取 {0}…", "Ready": "就绪", "Refresh": "刷新", "Refresh cache statistics": "刷新缓存统计", + "Refresh pending": "等待刷新", "Refresh the mcpp Package Index": "刷新 mcpp 包索引", "Refresh this view": "刷新此视图", "Refreshing the mcpp Package Index…": "正在刷新 mcpp 包索引…", "Registry": "Registry", "Reload the window to see this": "重载窗口后生效", + "Remove build directories mcpp no longer considers current?": "删除 mcpp 认为已不再使用的构建目录?", + "Remove the cache directory of earlier mcpp releases?": "删除旧版 mcpp 的缓存目录?", "Remove the pre-v1 cache": "清理 pre-v1 遗留缓存", + "Remove the whole target/ directory?": "删除整个 target/ 目录?", "Repository": "仓库", + "Reread locally": "重新读取本地索引", "Reset": "重置", "Reset the invalid value to the default": "将无效值重置为默认值", "Reset this workspace's cache": "重置本工作区缓存", + "Resolved in lockfile": "锁定解析", "Resolved {0}": "已解析 {0}", "Resolved —": "已解析 —", "Restart language service": "重启语言服务", "Restart the semantic engine": "重启语义引擎", "Result: {0}": "结果:{0}", + "Retry reading details": "重新读取详情", "Root: {0}": "根目录:{0}", "Run": "运行", "Run the build tool in a terminal": "在终端运行构建工具", "Run “mcpp new {0}” in {1}, create the project folder {2} and open it.": "将在 {1} 执行 “mcpp new {0}”,创建项目文件夹 {2} 并打开它。", "Runtime dependencies": "运行时依赖", "Save settings to": "保存设置到", + "Scroll to zoom · drag to pan": "滚轮缩放 · 按住拖动画布", "Search all registries": "在全部 registry 中搜索", "Search and add a dependency": "搜索并添加依赖", "Search and add a dependency…": "搜索并添加依赖…", + "Search other registries": "搜索其它 registry", "Search packages": "搜索包", + "Search preview: only the fields returned by mcpp search are available.": "搜索预览:仅展示 mcpp search 返回的字段。", + "Search previews cannot be added. Open a complete local descriptor first.": "搜索预览无法直接添加,请先打开完整的本地包描述。", "Search settings": "搜索设置", "Searching all registries failed (exit {0}); showing the local index only.": "搜索全部 registry 失败(退出码 {0});只显示本地索引。", "Searching all registries…": "正在搜索全部 registry…", + "Searching other registries…": "正在搜索其它 registry…", + "Select a node to explore its relationships.": "选择节点查看关联。", + "Select an mcpp project before adding this library.": "请先选择 mcpp 项目,再添加此库。", "Select analysis context": "重选分析上下文", "Select the global default toolchain": "选择全局默认工具链", + "Selected": "选中", + "Selected node": "已选节点", "SemVer version dependency": "SemVer 版本依赖", "Set as global default": "设为全局默认", + "Set index path": "设置索引路径", "Set the global default toolchain": "设置全局默认工具链", "Setting the global default toolchain failed (exit code {0}). See the mcpp output channel.": "设置全局默认工具链失败(退出码 {0})。请查看 mcpp 输出频道。", "Settings": "设置", @@ -270,10 +403,16 @@ "Shared build cache": "共享构建缓存", "Show advanced settings": "显示高级设置", "Show cache entry details for {0}": "查看缓存条目 {0} 的详情", + "Show output": "查看输出", "Show running tasks": "显示正在运行的任务", "Show toolchains": "查看工具链", "Simulates mcpp cache gc --max-size: the estimate is a local projection, so mcpp's own policy decides in the end.": "模拟 mcpp cache gc --max-size:这里的估算只是本地推算,最终仍以 mcpp 自身的策略为准。", "Size": "大小", + "Source": "源码", + "Source and diagnostics": "来源与诊断", + "Source dependency": "源码依赖", + "Source details": "来源详情", + "Source is unavailable for this module.": "此模块的源码不可用。", "Stale artifacts: about {0}": "其中过期产物约 {0}", "Standard": "标准", "Switch to {0}": "切换到 {0}", @@ -285,14 +424,18 @@ "Takes effect on the next build": "下次构建时生效", "Takes effect on the next clean": "下次清理时生效", "Target": "目标", + "Target project": "目标项目", "Targets": "目标", "Task arguments: {0}": "任务参数:{0}", "Test": "测试", + "Tests": "测试", "The C++ Modules extension ({0}) is not installed or is disabled.": "C++ Modules 扩展({0})未安装或已禁用。", "The build was cancelled; the C++ Modules language service was not refreshed.": "构建已取消;C++ 模块语言服务未刷新。", "The compatible spec {0} carrying target semantics is handed to mcpp to install.": "将把携带 target 语义的兼容 spec {0} 交给 mcpp 安装。", "The compatible spec {0}, which may carry target semantics, is handed to mcpp to install, and mcpp validates it in the end.": "将把可能携带 target 语义的兼容 spec {0} 交给 mcpp 安装,最终由 mcpp 校验。", + "The current environment platform is not recognized by this index.": "索引无法识别当前环境平台。", "The current mcpp toolchain list output is not recognised; the raw output is kept in the mcpp output channel, so check the mcpp version.": "无法识别当前 mcpp toolchain list 输出;原始输出已保留在 mcpp 输出频道,请检查 mcpp 版本。", + "The dependency declaration changed. Review mcpp.toml before adding it.": "依赖声明已变化,请先检查 mcpp.toml 再添加。", "The destination already exists: {0}. Choose another project name or location.": "目标路径已存在:{0}。请更换项目名或位置。", "The global default pair is set to {0} + host target. The mcpp.toml/target configuration of the current project can still override it.": "将把全局默认对设为 {0} + host target。当前项目的 mcpp.toml/target 配置仍可能覆盖它。", "The index folders contain no descriptors.": "索引目录里没有描述符。", @@ -300,8 +443,10 @@ "The mcpp build failed (exit code {0}); the C++ Modules language service re-read the existing build description.": "mcpp 构建失败(退出码 {0});C++ 模块语言服务已重新读取现有构建描述。", "The mcpp build finished; the C++ Modules language service has been refreshed.": "mcpp 构建完成,C++ 模块语言服务已刷新。", "The mcpp global default is now {0} + host target. Cleaning the old toolchain artifacts and rebuilding is recommended.": "mcpp 全局默认已更新为 {0} + host target。建议清理旧工具链产物后重新构建。", + "The package descriptor is missing. Reread the local index.": "包描述不存在,请重新读取本地索引。", "The program did not build; see the task terminal for the compiler output.": "程序未构建成功;编译器输出见任务终端。", "The project currently overrides the global default; this only changes the current mcpp global configuration": "项目当前覆盖全局默认;这里只修改 mcpp 当前全局配置", + "The project manifest is missing or unreadable.": "项目清单不存在或无法读取。", "The project name must not be . or ..": "项目名不能是 . 或 ..", "The project name must not be a Windows reserved device name.": "项目名不能是 Windows 保留设备名", "The project name must not be empty.": "项目名不能为空", @@ -317,23 +462,34 @@ "The shared build cache is not available.": "共享构建缓存不可用。", "The shared build cache is {0}, at or above the {1} warning threshold.": "共享构建缓存为 {0},已达到或超过 {1} 的告警阈值。", "The shared build cache is {0}. Raise or clear mcpp.cache.warnAboveGiB to change when this appears.": "共享构建缓存为 {0}。调高或清空 mcpp.cache.warnAboveGiB 可改变告警时机。", + "The source graph is incomplete. Refresh after indexing finishes.": "数据尚不完整,可在索引完成后刷新。", + "The source graph is incomplete. Some modules may be omitted.": "源图数据不完整,部分模块可能尚未包含。", "The target axis is shown read-only; to select a target use the mcpp CLI": "target 轴只读展示;选择 target 请使用 mcpp CLI", "The version is required: mcpp accepts an exact version only.": "必须指定版本:mcpp 只接受精确版本。", + "The workspace is not trusted; mcpp itself was not probed.": "工作区未受信任;未探测 mcpp 本身。", + "The workspace is not trusted; the other registries were not searched.": "工作区未受信任;未搜索其他 registry。", "The {0} largest cache labels, by bytes.": "按字节数排名的前 {0} 个缓存标签。", "There is no pre-v1 cache to remove.": "没有可清理的 pre-v1 缓存。", + "They answer the same C++ files, so results appear twice. Click to turn their C++ language features off; C++ Modules asks whether for this workspace or everywhere.": "它们也在处理同一批 C++ 文件,结果会出现两次。点击即可关闭它们的 C++ 语言功能;C++ Modules 会询问只对本工作区还是对所有地方生效。", + "This deletes every build directory of this project. The next build starts from scratch. The shared build cache is not touched.": "这会删除本工程的全部构建目录,下次构建从头开始。共享构建缓存不受影响。", + "This dependency name is ambiguous. Use a qualified package name in mcpp.toml.": "此依赖名称有歧义,请在 mcpp.toml 中使用完整包名。", "This descriptor declares no dependencies.": "此描述符没有声明依赖。", "This does not clean the global BMI cache.": "此操作不会清理全局 BMI 缓存。", "This index publishes no version for any platform.": "此索引没有为任何平台发布版本。", "This index publishes no version for this platform, so there is nothing to add.": "此索引没有为当前平台发布版本,因此无法添加。", + "This is a search preview. Set an index path containing this package to read its complete details.": "这是搜索预览。将索引路径设置为包含此包的目录后,可读取完整详情。", "This is the current-directory view; overrides from the project or a parent configuration are decided by the actual build": "当前目录视图;项目或父级配置的覆盖以实际构建为准", "This is the current-directory view; the value mcpp build resolves is authoritative": "当前目录视图;实际生效值以 mcpp build 解析为准", "This mcpp build does not recognise that command; update mcpp or check the spelling.": "此 mcpp 版本不认识该命令;请升级 mcpp 或检查拼写。", "This package has no test project in the index, so there is no example to show.": "此包在索引里没有示例工程,因此没有示例可显示。", "This package is not in the local index any more.": "此包已不在本地索引中。", "This panel changes mcpp-vscode settings only; the C++ Modules extension ({0}) keeps its own mcppls.* settings and this panel never writes them.": "本面板只修改 mcpp-vscode 的设置;C++ Modules 扩展({0})自行管理其 mcppls.* 设置,本面板不会写入它们。", + "This project declares no dependencies": "此项目未声明依赖", "This project may not be using this value": "当前项目可能没有使用此值", + "This project uses a source dependency. Edit its manifest to change the source.": "项目已声明源码依赖,请编辑清单修改来源。", "This runs mcpp build and has the C++ Modules extension re-read the build description; it does not change the toolchain, mcpp.toml or any language service setting.": "将执行 mcpp build,并由 C++ Modules 扩展重新读取构建描述;不会修改工具链、mcpp.toml 或任何语言服务设置。", "This workspace has no mcpp.toml.": "当前工作区没有找到 mcpp.toml。", + "This workspace is not trusted, so mcpp is not run; the versions below come from the descriptor's text.": "工作区未受信任,因此不运行 mcpp;下面的版本来自描述符文本。", "This workspace is not trusted, so mcpp will not run and the C++ Modules language service will not refresh. Trust the workspace first.": "当前工作区未受信任,不会执行 mcpp 或刷新 C++ 模块语言服务。请先信任工作区。", "This workspace is not trusted. mcpp commands may run external programs named by workspace settings; trust the workspace first.": "当前工作区未受信任。mcpp 命令可能执行工作区设置指定的外部程序,请先信任工作区。", "This workspace is not trusted. mcpp commands that write are disabled until you trust it.": "当前工作区未受信任。会写盘的 mcpp 命令在信任工作区之前不会执行。", @@ -342,33 +498,53 @@ "Toolchain": "工具链", "Toolchain managed by mcpp": "mcpp 管理的工具链", "Toolchain {0} installed. Choose a global default from the latest list?": "工具链 {0} 安装完成。是否从最新列表中选择全局默认?", + "Trust this workspace to run mcpp and add dependencies.": "信任此工作区后,才能运行 mcpp 和添加依赖。", "Unavailable": "暂无元数据", "Unexpected error: {0}": "发生未预期错误:{0}", "Unknown": "未知", + "Up to 3 dependency levels · {0} packages · {1} edges": "最多 3 层依赖 · {0} 个包 · {1} 条关系", + "Update mcpp index": "更新 mcpp 索引", + "Update mcppls": "更新 mcppls", + "Updating mcpp index…": "正在更新 mcpp 索引…", + "Updating the global mcpp index; a configured custom checkout is only reread.": "正在更新全局 mcpp 索引;已配置的自定义检出目录仅会被重新读取。", + "Usage": "用法", "Use": "用法", "User": "用户", "User settings": "用户设置", "VS Code could not open {0}. The link is on your clipboard.": "VS Code 无法打开 {0},链接已复制到剪贴板。", "Values shown for {0}": "以下值适用于 {0}", "Verify the cache": "校验缓存", + "Verify the shared build cache": "校验共享构建缓存", "Verify the shared cache": "校验共享缓存", + "Version": "版本", + "Version availability could not be confirmed. Retry reading this descriptor.": "暂时无法确认版本可用性,请重新读取包描述。", "Versions": "版本", "Versions ({0})": "版本({0})", + "Versions are from descriptor text; mcpp will confirm availability when adding.": "版本来自描述符文本,添加时将由 mcpp 确认可用性。", "Versions mcpp aggregates by family; this operation installs for the host target": "mcpp 按 family 聚合的可用版本;本操作按 host target 安装", + "View limit reached. Focus a node to explore its dependencies.": "已达到当前视图上限,可聚焦节点继续查看。", + "View options": "视图", "What the descriptor declares. The resolved version lives in a project's mcpp.lock, not here.": "这里显示描述符声明的依赖。解析后的版本在工程的 mcpp.lock 里,不在这里。", "Working directory: {0}": "工作目录:{0}", "Workspace": "工作区", "Workspace folder": "工作区文件夹", "Workspace member declarations": "工作空间成员声明", "Workspace settings": "工作区设置", + "Zoom in": "放大", + "Zoom out": "缩小", + "a project's name is one directory name: {0}": "工程名必须是单个目录名:{0}", "added": "已添加", + "build": "构建", + "conditional": "条件", "convention {0}": "约定 {0}", "dev dependency": "dev 依赖", "git · {0}": "git · {0}", "host default": "host 默认", + "index": "索引", "latest {0}": "最新 {0}", "mcpp CLI operation failed: {0}": "mcpp CLI 操作失败:{0}", "mcpp Package Index refreshed: {0} package(s) from {1} index folder(s).": "mcpp 包索引已刷新:{0} 个包,来自 {1} 个索引目录。", + "mcpp add failed (exit {0}). See output for details.": "mcpp add 失败(退出码 {0}),请查看输出了解详情。", "mcpp add failed with exit code {0}.": "mcpp add 失败,退出码 {0}。", "mcpp add failed with exit code {0}: {1}": "mcpp add 失败,退出码 {0}:{1}", "mcpp add needs an exact version: mcpp add {0}@.": "mcpp add 需要精确版本:mcpp add {0}@。", @@ -382,11 +558,14 @@ "mcpp clean --dry-run": "mcpp clean --dry-run", "mcpp decides whether the compiler prefix is a valid triple; when it is, it may download a larger toolchain package for that target.": "mcpp 会判断编译器前缀是否为有效 triple;有效时可能下载对应 target 的较大工具链包。", "mcpp does not download or install MSVC; it detects Visual Studio and points to the official installation guide when it is missing.": "mcpp 不会下载或安装 MSVC;它会检测 Visual Studio,并在缺失时给出官方安装指引。", + "mcpp drops least-recently-used entries until the cache fits. Projects that used a dropped entry rebuild it.": "mcpp 按最近最少使用的顺序删除条目,直到缓存符合预算。用到被删条目的工程会重新构建。", + "mcpp emit build-database printed no document": "mcpp emit build-database 没有输出文档", "mcpp finished {0}. This first release does not change the target default; to set one, use the mcpp CLI with --target.": "mcpp 已完成 {0}。首版插件不修改 target 默认;如需设为默认,请使用带 --target 的 mcpp CLI。", "mcpp global configuration": "mcpp 全局配置", "mcpp has no global default toolchain yet": "mcpp 尚未设置全局默认工具链", "mcpp index update failed with exit code {0}": "mcpp index update 失败,退出码 {0}", "mcpp is installed but the environment is not ready; run `mcpp self doctor` to see what is missing.": "mcpp 已安装但环境尚未就绪;运行 `mcpp self doctor` 查看缺少什么。", + "mcpp is not available": "mcpp 不可用", "mcpp library ecosystem": "mcpp 库生态", "mcpp list item effective for this directory; the actual build resolution may be affected by a parent mcpp workspace": "mcpp list 当前目录有效项;实际构建解析可能受父级 mcpp 工作区影响", "mcpp list toolchain for this directory": "mcpp list 当前目录工具链", @@ -396,14 +575,18 @@ "mcpp pack packaging configuration": "mcpp pack 打包配置", "mcpp rejected the command line; check the arguments and run it from the project root.": "mcpp 拒绝了命令行;请检查参数,并在工程根目录运行。", "mcpp reported an internal error; re-run with the mcpp output channel open and report it.": "mcpp 报告了内部错误;请打开 mcpp 输出频道重跑并反馈。", + "mcpp search printed no catalogue": "mcpp search 没有输出包目录", "mcpp settings": "mcpp 设置", "mcpp toolchain list failed (exit code {0}). See the mcpp output channel.": "mcpp toolchain list 失败(退出码 {0})。请查看 mcpp 输出频道。", "mcpp toolchain management": "mcpp 工具链管理", "mcpp toolchain {0} is installed (no target specified, the host target is used).": "将安装 mcpp 工具链 {0}(不指定 target,使用 host target)。", "mcpp toolchains and targets": "mcpp 工具链与 target", + "mcpp was not found": "未找到 mcpp", "mcpp will detect the system MSVC ({0}).": "将调用 mcpp 检测系统 MSVC({0})。", "mcpp xpkg parse could not read this descriptor; the versions below come from its text, which is less authoritative.": "mcpp xpkg parse 无法读取此描述符;下面的版本来自文本解析,权威性较低。", + "mcpp {0} at {1}": "mcpp {0},位于 {1}", "mcpp {0} failed with exit code {1}": "mcpp {0} 失败,退出码 {1}", + "mcpp {0} predates the control contract ({1}): builds run without events, records or launch descriptors": "mcpp {0} 早于控制契约({1}):构建不提供事件、结果记录与启动描述", "mcpp.toml could not be read": "无法读取 mcpp.toml", "mcpp: Build": "mcpp: 构建", "mcpp: Clean": "mcpp: 清理", @@ -414,22 +597,37 @@ "mcpp: moved {0} setting(s).": "mcpp:已移动 {0} 个设置。", "mcpp: quick menu": "mcpp: 快捷菜单", "mcpp: {0}": "mcpp:{0}", + "mcppls at {0} did not report its version: {1}": "{0} 处的 mcppls 未报告版本:{1}", + "mcppls was not found: C++ files have no completion, navigation or diagnostics from mcpp's build. Install the C++ Modules language server ({0} or later).": "未找到 mcppls:C++ 文件没有基于 mcpp 构建的补全、跳转与诊断。请安装 C++ Modules 语言服务({0} 或更新版本)。", "mcppls {0}": "mcppls {0}", + "mcppls {0} at {1}": "mcppls {0},位于 {1}", + "mcppls {0} predates mcpp's result record: a build does not refresh it. Update mcppls to {1} or later.": "mcppls {0} 早于 mcpp 的结果记录:构建后它不会刷新。请将 mcppls 更新到 {1} 或更新版本。", "more than {0} day(s)": "超过 {0} 天", "more than {0} day(s) ago": "超过 {0} 天前", + "no such package": "没有这个包", "not read yet": "尚未读取", "openkal-compat": "openkal-compat", "openkal-ecosystem": "openkal-ecosystem", "other registry": "其它 registry", "path · {0}": "路径 · {0}", "resolved {0}": "已解析 {0}", + "runs after the job in progress": "在当前任务结束后运行", + "the control contract is available": "控制契约可用", + "the program could not be built": "程序未能构建", "the workspace is not trusted": "工作区未受信任", + "the workspace is not trusted: mcpp runs with effects denied": "工作区未受信任:mcpp 在禁止副作用的情况下运行", + "the workspace is trusted": "工作区已受信任", + "this action needs a trusted workspace": "此操作需要受信任的工作区", + "this action was not confirmed": "此操作未经确认", "this platform": "当前平台", + "this program runs through {0}; the debugger starts {0} and reads the program's symbols when it is loaded": "此程序经由 {0} 运行;调试器启动 {0},并在程序加载时读取其符号", "under {0} day(s)": "少于 {0} 天", "unknown": "未知", "unknown error": "未知错误", "upstream mcpp.toml": "上游 mcpp.toml", "uses platform interfaces": "使用平台接口", + "xlings at {0}": "xlings,位于 {0}", + "xlings is not on PATH; mcpp uses the one it bundles": "PATH 中没有 xlings;mcpp 使用其自带的 xlings", "{0}": "{0}", "{0} cache entries are incomplete; run mcpp cache verify to see which ones.": "有 {0} 个缓存条目不完整;运行 mcpp cache verify 可查看具体是哪些。", "{0} descriptor(s) from {1} local index folder(s): {2}. Read offline.": "从 {1} 个本地索引目录读到 {0} 个描述符:{2}。离线读取。", @@ -453,166 +651,13 @@ "{0} · version {1}": "{0} · 版本 {1}", "{0} · {1}": "{0} · {1}", "{0} · {1} file(s)": "{0} · {1} 个文件", + "{0} · {1} packages · local": "{0} · {1} 个包 · 本地", "{0} · {1} · {2}": "{0} · {1} · {2}", "{0}: done.": "{0}:完成。", "{0}: the installed C++ Modules does not offer this action.": "{0}:已安装的 C++ Modules 不提供该操作。", "{0}{1}": "{0}{1}", "{0}–{1} day(s)": "{0}–{1} 天", "{0}–{1} day(s) ago": "{0}–{1} 天前", - "✓ Has examples": "✓ 有示例", - "Bring it into your code": "在代码里引入", - "Copy": "复制", - "Copied to the clipboard.": "已复制到剪贴板。", - "Copying…": "复制中…", - "Could not write the clipboard.": "无法写入剪贴板。", - "The workspace is not trusted; mcpp itself was not probed.": "工作区未受信任;未探测 mcpp 本身。", - "This workspace is not trusted, so mcpp is not run; the versions below come from the descriptor's text.": "工作区未受信任,因此不运行 mcpp;下面的版本来自描述符文本。", - "The workspace is not trusted; the other registries were not searched.": "工作区未受信任;未搜索其他 registry。", - "Only C++ Modules is serving C++": "仅 C++ Modules 在提供 C++ 语言服务", - "No other C++ language service (C/C++, clangd, ccls) is active, so no result is shown twice.": "没有其他 C++ 语言服务(C/C++、clangd、ccls)在工作,结果不会重复出现。", - "Other C++ language services": "其他 C++ 语言服务", - "They answer the same C++ files, so results appear twice. Click to turn their C++ language features off; C++ Modules asks whether for this workspace or everywhere.": "它们也在处理同一批 C++ 文件,结果会出现两次。点击即可关闭它们的 C++ 语言功能;C++ Modules 会询问只对本工作区还是对所有地方生效。", - "Libraries": "库", - "Source details": "来源详情", - "Other registries": "其它 registry", - "Set index path": "设置索引路径", - "Update mcpp index": "更新 mcpp 索引", - "Show output": "查看输出", - "Clear search": "清空搜索", - "Search other registries": "搜索其它 registry", - "Declared": "已声明", - "Reread locally": "重新读取本地索引", - "Could not read the index: {0}": "无法读取索引:{0}", - "Searching other registries…": "正在搜索其它 registry…", - "Other registry": "其它 registry", - "Official index": "官方索引", - "Custom index": "自定义索引", - "Browse libraries; select an mcpp project in the detail page to add dependencies.": "可以浏览库;请在详情页选择 mcpp 项目后添加依赖。", - "No local mcpp-index found": "未找到本地 mcpp-index", - "{0} · {1} packages · local": "{0} · {1} 个包 · 本地", - "Target project": "目标项目", - "Choose project": "选择项目", - "Environment platform": "当前环境平台", - "Version": "版本", - "Other platforms (read only)": "其它平台(只读)", - "Resolved in lockfile": "锁定解析", - "Source dependency": "源码依赖", - "No verified import or header path is available locally. See the repository or index site for usage.": "本地没有可验证的模块名或头文件路径,请查看仓库或索引站的用法说明。", - "From the index's example source": "来自索引示例源码", - "Source and diagnostics": "来源与诊断", - "Reading package details…": "正在读取包详情…", - "Adding dependency…": "正在添加依赖…", - "Changing dependency groups is not supported here. Edit mcpp.toml to move the declaration.": "此处暂不支持迁移依赖分组,请编辑 mcpp.toml 移动声明。", - "Retry reading details": "重新读取详情", - "Open mcpp.toml": "打开 mcpp.toml", - "Open source file": "打开源文件", - "Search preview: only the fields returned by mcpp search are available.": "搜索预览:仅展示 mcpp search 返回的字段。", - "Copied": "已复制", - "Copy failed": "复制失败", - "Opened in your browser.": "已在浏览器中打开。", - "Could not open the browser. Link copied to clipboard.": "无法打开浏览器,链接已复制到剪贴板。", - "Could not open the browser or copy the link: {0}": "无法打开浏览器或复制链接:{0}", - "Could not add the dependency. See output for details.": "无法添加依赖,请查看输出了解详情。", - "Could not read package details. See output for details.": "无法读取包详情,请查看输出了解详情。", - "This is a search preview. Set an index path containing this package to read its complete details.": "这是搜索预览。将索引路径设置为包含此包的目录后,可读取完整详情。", - "Search previews cannot be added. Open a complete local descriptor first.": "搜索预览无法直接添加,请先打开完整的本地包描述。", - "The package descriptor is missing. Reread the local index.": "包描述不存在,请重新读取本地索引。", - "Trust this workspace to run mcpp and add dependencies.": "信任此工作区后,才能运行 mcpp 和添加依赖。", - "Select an mcpp project before adding this library.": "请先选择 mcpp 项目,再添加此库。", - "This dependency name is ambiguous. Use a qualified package name in mcpp.toml.": "此依赖名称有歧义,请在 mcpp.toml 中使用完整包名。", - "This project uses a source dependency. Edit its manifest to change the source.": "项目已声明源码依赖,请编辑清单修改来源。", - "Version availability could not be confirmed. Retry reading this descriptor.": "暂时无法确认版本可用性,请重新读取包描述。", - "No version is published for the current environment platform.": "当前环境平台没有可用的发布版本。", - "Already declared": "已声明", - "Descriptor-level dependencies; the selected version may differ. Resolved values refer to this project's lockfile.": "这里展示包描述中的依赖,所选版本的依赖可能不同;解析版本来自当前项目的锁文件。", - "mcpp add failed (exit {0}). See output for details.": "mcpp add 失败(退出码 {0}),请查看输出了解详情。", - "Choose the target mcpp project": "选择目标 mcpp 项目", - "Dependencies will be added to this project's mcpp.toml": "依赖将添加到此项目的 mcpp.toml", - "Updating the global mcpp index; a configured custom checkout is only reread.": "正在更新全局 mcpp 索引;已配置的自定义检出目录仅会被重新读取。", - "The current environment platform is not recognized by this index.": "索引无法识别当前环境平台。", - "Versions are from descriptor text; mcpp will confirm availability when adding.": "版本来自描述符文本,添加时将由 mcpp 确认可用性。", - "Platforms and versions": "平台与版本", - "Add dependency": "添加依赖", - "Usage": "用法", - "Dependency type": "依赖类型", - "Project dependency": "项目依赖", - "Development dependency": "开发依赖", - "Build dependency": "构建依赖", - "Add development dependency": "添加开发依赖", - "Build dependencies are used by the build script. Copy this entry into mcpp.toml; mcpp add does not support this group yet.": "构建依赖供构建脚本使用;当前 mcpp add 尚不支持此分组,请复制此项并编辑 mcpp.toml。", - "Changing this declaration requires a manifest edit. Copy the entry and update its dependency group in mcpp.toml.": "请复制声明并在 mcpp.toml 中调整依赖分组;已有声明不会自动迁移。", - "The dependency declaration changed. Review mcpp.toml before adding it.": "依赖声明已变化,请先检查 mcpp.toml 再添加。", - "Updating mcpp index…": "正在更新 mcpp 索引…", - "Index update failed; showing the last available local snapshot.": "索引更新失败,继续显示上次可用的本地快照。", - "Index updated; {0} local packages.": "索引已更新,本地共 {0} 个包。", - "Bundled official index tests · commit {0}": "插件内置官方索引测试 · 提交 {0}", - "Project dependency graph": "项目依赖图", - "Copy Mermaid": "复制 Mermaid", - "Up to 3 dependency levels · {0} packages · {1} edges": "最多 3 层依赖 · {0} 个包 · {1} 条关系", - "Edges come from manifests and local index descriptors; lockfile versions are shown when available. This is a declaration graph, not a resolved build graph. Dashed nodes have no local dependency metadata; conditional edges may not apply to this environment.": "关系来自项目清单和本地索引描述符;有锁定版本时显示锁定版本。这是声明关系图,不代表实际构建解析结果。虚线节点缺少本地依赖元数据,条件关系可能不适用于当前环境。", - "Large graph truncated at 120 nodes or 240 edges.": "大型依赖图已截断(最多 120 个节点或 240 条关系)。", - "Fit": "适应窗口", - "Mermaid source": "Mermaid 源码", - "Could not render the graph. Copy Mermaid source or refresh to retry.": "依赖图渲染失败,可复制 Mermaid 源码或刷新重试。", - "Could not read project dependencies: {0}": "无法读取项目依赖:{0}", - "Open an mcpp project first.": "请先打开一个 mcpp 项目。", - "The project manifest is missing or unreadable.": "项目清单不存在或无法读取。", - "Reading project dependencies…": "正在读取项目依赖…", - "Source": "源码", - "Open read-only source": "打开只读源码", - "Dependency graph": "依赖图", - "Maximum dependency depth: 3": "最多展示 3 层依赖", - "Zoom out": "缩小", - "Zoom in": "放大", - "Legend and source": "图例与源码", - "Project": "项目", - "Declaration graph · dashed edges are conditional · lockfile supplies versions": "声明关系图 · 虚线为条件依赖 · 锁文件提供版本", - "index": "索引", - "build": "构建", - "conditional": "条件", - "Scroll to zoom · drag to pan": "滚轮缩放 · 按住拖动画布", - "C++ Modules Deps": "C++ Modules 依赖图", - "No module relationships were found for this project.": "此项目尚无模块关系。", - "View limit reached. Focus a node to explore its dependencies.": "已达到当前视图上限,可聚焦节点继续查看。", - "The source graph is incomplete. Refresh after indexing finishes.": "数据尚不完整,可在索引完成后刷新。", - "Expand next level": "展开下一层", - "Selected node": "已选节点", - "Graph view": "图视图", - "Packages": "包依赖", - "Depth": "深度", - "Find a node…": "查找节点…", - "Back to project": "返回项目", - "Select a node to explore its relationships.": "选择节点查看关联。", - "Collapse": "收起", - "Focus": "聚焦", - "Packages show declarations; modules show mcppls imports. External modules stop after one hop.": "包图显示声明关系;模块图来自 mcppls,外部模块只显示一层。", - "Source is unavailable for this module.": "此模块的源码不可用。", - "Choose a module source file": "选择模块源码文件", - "The source graph is incomplete. Some modules may be omitted.": "源图数据不完整,部分模块可能尚未包含。", - "Could not export this graph. Try SVG or a smaller view.": "无法导出此图,请尝试 SVG 或更小的视图。", - "Entry group": "入口分组", - "Selected": "选中", - "Export SVG": "导出 SVG", - "Export PNG": "导出 PNG", - "Dependencies depth": "依赖深度", - "Importers depth": "父节点深度", - "Previous entries": "上一批入口", - "Next entries": "下一批入口", - "Back": "后退", - "Locate focus": "定位焦点", - "Locate selected": "定位选中", - "Open source": "打开源码", - "Expand importers": "展开父节点", - "Collapse importers": "折叠父节点", - "Focus this result": "以此结果为焦点", - "Dependencies unavailable — click to retry": "暂时无法读取依赖,点击重试", - "Reading dependencies…": "正在读取依赖…", - "This project declares no dependencies": "此项目未声明依赖", - "Refresh pending": "等待刷新", - "Main": "主程序", - "Tests": "测试", - "Other": "其他", - "Export": "导出", - "View options": "视图", - "Node actions": "节点操作" + "…": "…", + "✓ Has examples": "✓ 有示例" } diff --git a/spec/settings.json b/spec/settings.json index e5bc95f..c7c5a4b 100644 --- a/spec/settings.json +++ b/spec/settings.json @@ -1087,7 +1087,7 @@ "order": 5, "tier": "advanced", "applies": "restart", - "since": "0.10.0", + "since": "1.0.0", "title": "Set the mcpp-ide backend path", "description": "The mcpp-ide program the extension starts. Empty: the backend shipped with the extension, then the one xlings installed, then PATH." }, @@ -1100,7 +1100,7 @@ "order": 30, "tier": "public", "applies": "immediate", - "since": "0.10.0", + "since": "1.0.0", "title": "Build when a file is saved", "description": "Start a build of the file's project when a source or mcpp.toml is saved. A save while a build waits replaces it; a running build is cancelled and started again." }, @@ -1117,10 +1117,23 @@ "order": 31, "tier": "public", "applies": "immediate", - "since": "0.10.0", + "since": "1.0.0", "title": "Choose the build profile", "description": "The profile build, run, test and debug use: dev (unoptimised, debug information) or release." }, + { + "key": "mcpp.build.target", + "type": "string", + "default": "", + "scope": "resource", + "group": "tasks", + "order": 33, + "tier": "public", + "applies": "immediate", + "since": "1.0.0", + "title": "Choose the build target", + "description": "The target build, run, test, debug and pack use, as mcpp names it (x86_64-linux-musl, x86_64-openkal). Empty: this machine. The Targets panel lists the targets and the platform that configures each." + }, { "key": "mcpp.trust.denyEffects", "type": "array", @@ -1133,7 +1146,7 @@ "order": 10, "tier": "advanced", "applies": "immediate", - "since": "0.10.0", + "since": "1.0.0", "title": "Effects denied in an untrusted workspace", "description": "What mcpp may not do while the workspace is not trusted (mcpp --deny): a run that needs one of them stops before it and says so. Trusting the workspace lifts the list." }, @@ -1153,9 +1166,9 @@ "order": 32, "tier": "public", "applies": "immediate", - "since": "0.10.0", + "since": "1.0.0", "title": "Choose the debugger", "description": "The debug adapter a debug session uses. auto: CodeLLDB when it is installed, then the C/C++ extension's gdb or lldb, then lldb-dap." } ] -} \ No newline at end of file +} diff --git a/src/bin/dev.cpp b/src/bin/dev.cpp new file mode 100644 index 0000000..a6a3170 --- /dev/null +++ b/src/bin/dev.cpp @@ -0,0 +1,496 @@ +// mcpp-ide-dev: the repository's own tools, as one program of this package (no script runtime is +// needed beside mcpp). +// +// mcpp-ide-dev capture [--mcpp PATH] [--out DIR] +// The golden fixtures under protocol/fixtures, from a real mcpp: the envelopes, streams and +// records the backend reads. The mock mcpp and both adapters' tests replay them, so a change in +// mcpp's contract shows up as a diff here first. +// mcpp-ide-dev gen vscode --out DIR [--stage] [--backends DIR] +// The VS Code extension's declarations from spec/: package.json (vscode/package.json with the +// generated commands, keybindings, menus and configuration), package.nls.json and +// package.nls.zh-cn.json. With --stage, also the files the extension ships (vscode/out, media, +// syntaxes, the webui, README, CHANGELOG, LICENSE, and bin// from --backends): the +// directory `vsce package` packs. +// mcpp-ide-dev gen jetbrains --out DIR +// The CLion plugin's declarations from spec/: META-INF/mcpp-actions.xml (included by +// plugin.xml) and the message bundles messages/McppClionBundle[_zh_CN].properties. +// mcpp-ide-dev check-i18n +// Every runtime string the backend and the adapters pass to t(...) has a Chinese entry in +// spec/i18n/runtime.zh-cn.json; every editor string a Chinese one in manifest.zh-cn.json. +// +// Nothing generated is written into the repository: the outputs go where the adapters' builds put +// them (vscode/dist, jetbrains/build). +import std; +import nlohmann.json; +import mcpplibs.os; + +namespace { + +using Json = nlohmann::json; +namespace fs = std::filesystem; + +std::string slurp(const fs::path& p) { + std::ifstream in(p, std::ios::binary); + return std::string(std::istreambuf_iterator(in), {}); +} + +void spit(const fs::path& p, std::string_view text) { + fs::create_directories(p.parent_path()); + if (slurp(p) == text) return; + std::ofstream(p, std::ios::binary) << text; +} + +Json read_json(const fs::path& p) { + auto doc = Json::parse(slurp(p), nullptr, false); + if (doc.is_discarded()) throw std::runtime_error(std::format("{}: not JSON", p.generic_string())); + return doc; +} + +std::string replace_all(std::string s, std::string_view from, std::string_view to) { + if (from.empty()) return s; + for (auto pos = s.find(from); pos != std::string::npos; pos = s.find(from, pos + to.size())) s.replace(pos, from.size(), to); + return s; +} + +// The repository: the nearest directory above the working one whose mcpp.toml is mcpp-ide's. +fs::path repo() { + std::error_code ec; + for (auto d = fs::current_path(ec); !d.empty(); d = d.parent_path()) { + if (slurp(d / "mcpp.toml").find("name = \"mcpp-ide\"") != std::string::npos) return d; + if (d == d.parent_path()) break; + } + throw std::runtime_error("run mcpp-ide-dev inside the mcpp-ide repository"); +} + +std::optional option(std::span args, std::string_view name) { + for (std::size_t i = 0; i + 1 < args.size(); ++i) if (args[i] == name) return args[i + 1]; + return std::nullopt; +} +bool flag(std::span args, std::string_view name) { + return std::ranges::find(args, std::string(name)) != args.end(); +} + +// ── capture ───────────────────────────────────────────────────────────────── + +struct Ran { + int code = -1; + std::string out, err; +}; + +Ran run(const fs::path& program, std::vector args, const fs::path& cwd) { + mcpplibs::os::process::spawn_options o; + o.program = program; + o.args = std::move(args); + o.cwd = cwd; + o.in = mcpplibs::os::process::stdio::null; + o.env = {{"NO_COLOR", "1"}, {"MCPP_CLIENT", "mcpp-ide-fixtures"}}; + auto r = mcpplibs::os::process::run(o); + if (!r) return Ran{-1, {}, r.error().message()}; + return Ran{r->status.shell_code(), std::move(r->out), std::move(r->err)}; +} + +int capture(std::span args) { + const auto root = repo(); + fs::path mcpp = option(args, "--mcpp").value_or(""); + if (mcpp.empty()) { + auto found = mcpplibs::os::env::find_executable("mcpp"); + if (!found) throw std::runtime_error("no mcpp on PATH; name one with --mcpp"); + mcpp = *found; + } + const fs::path out = option(args, "--out").value_or((root / "protocol" / "fixtures").string()); + fs::create_directories(out); + const auto tmp = mcpplibs::os::dirs::temp() / std::format("mcppide-capture-{}", mcpplibs::os::process::self()->id); + fs::remove_all(tmp); + fs::create_directories(tmp); + const auto app = tmp / "app"; + const auto home = mcpplibs::os::dirs::home().value_or(fs::path{}).generic_string(); + // Paths in the fixtures are the temporary project's and the home's; the replay rewrites @ROOT@ to + // the directory a test runs in and @HOME@ to its home. + auto scrub = [&](std::string text) { + text = replace_all(std::move(text), app.generic_string(), "@ROOT@"); + if (!home.empty()) text = replace_all(std::move(text), home, "@HOME@"); + return text; + }; + auto save = [&](std::string_view name, std::string text) { spit(out / name, scrub(std::move(text))); }; + + auto version = run(mcpp, {"--version"}, tmp); + save("version.txt", version.out.substr(0, version.out.find('\n') + 1)); + save("protocol-version.json", run(mcpp, {"--protocol-version"}, tmp).out); + if (run(mcpp, {"new", "app"}, tmp).code != 0) throw std::runtime_error("mcpp new app failed"); + + save("build-ok.ndjson", run(mcpp, {"build", "--message-format", "json"}, app).out); + { + const auto last = read_json(app / "target" / ".last-result.json"); + save("result-ok.json", read_json(last["data"]["result"].get()).dump(2) + "\n"); + } + save("launch.json", run(mcpp, {"run", "--print-launch"}, app).out); + save("test.ndjson", run(mcpp, {"test", "--message-format", "json"}, app).out); + save("test-list.ndjson", run(mcpp, {"test", "--list", "--message-format", "json"}, app).out); + save("build-database.json", run(mcpp, {"emit", "build-database", "--format", "json"}, app).out); + save("index-list.json", run(mcpp, {"index", "list", "--format", "json"}, app).out); + save("pack-formats.json", run(mcpp, {"pack", "--list-formats"}, app).out); + save("self-env.json", run(mcpp, {"self", "env", "--format", "json"}, app).out); + + // A developer's home holds hundreds of cache entries and the index hundreds of packages; the + // fixtures keep enough of each to exercise every field. + auto trimmed = [&](std::string text, std::string_view key, std::size_t n) { + auto doc = Json::parse(text, nullptr, false); + if (doc.is_discarded() || !doc.contains("data") || !doc["data"].contains(key)) return text; + auto& list = doc["data"][std::string(key)]; + if (list.is_array() && list.size() > n) list.erase(list.begin() + static_cast(n), list.end()); + return doc.dump(2) + "\n"; + }; + save("search.json", trimmed(run(mcpp, {"search", "--format", "json"}, app).out, "packages", 60)); + save("cache-list.json", trimmed(run(mcpp, {"cache", "list", "--format", "json"}, app).out, "entries", 40)); + const auto toolchains = run(mcpp, {"toolchain", "list", "--format", "json"}, app).out; + save("toolchain-list.json", toolchains); + + // The platform a target's row names (mcpp's platforms, design 2026-10-28 §9): a build for the + // first target that has one, whose plan event carries the `platform` object. + { + auto doc = Json::parse(toolchains, nullptr, false); + std::string target; + if (!doc.is_discarded() && doc.contains("data") && doc["data"].contains("targets")) + for (const auto& t : doc["data"]["targets"]) + if (t.contains("platform") && t["platform"].is_object() && !t["platform"].value("name", "").empty()) { + target = t.value("target", ""); + break; + } + if (!target.empty()) { + save("build-platform.ndjson", run(mcpp, {"build", "--target", target, "--message-format", "json"}, app).out); + save("toolchain-list-platform.json", toolchains); + } else { + std::println(std::cerr, "note: this mcpp reports no platform per target; build-platform.ndjson not captured"); + } + } + + spit(app / "src" / "main.cpp", "int main() { return undeclared_name; }\n"); + save("build-failed.ndjson", run(mcpp, {"build", "--message-format", "json"}, app).out); + spit(app / "mcpp.toml", "[package\nname = \"app\"\n"); + save("build-manifest-error.ndjson", run(mcpp, {"build", "--message-format", "json"}, app).out); + fs::remove_all(tmp); + std::println("fixtures from {} in {}", version.out.substr(0, version.out.find('\n')), out.generic_string()); + return 0; +} + +// ── gen ───────────────────────────────────────────────────────────────────── + +struct Spec { + Json settings, commands, en, zh; +}; + +Spec load_spec(const fs::path& root) { + return Spec{read_json(root / "spec" / "settings.json"), read_json(root / "spec" / "commands.json"), + read_json(root / "spec" / "i18n" / "manifest.en.json"), read_json(root / "spec" / "i18n" / "manifest.zh-cn.json")}; +} + +bool offered_in(const Json& c, std::string_view editor) { + if (c.contains("editors") && c["editors"].is_array()) + return std::ranges::any_of(c["editors"], [&](const Json& e) { return e.is_string() && e.get() == editor; }); + const auto kind = c.contains("action") ? c["action"].value("kind", "") : std::string{}; + if (kind == "forward" || kind == "editor") return editor == "vscode"; + return true; +} + +// The `contributes` that come from spec/: commands, keybindings, menus, configuration. +void vscode_contributes(const Spec& spec, Json& contributes) { + Json commands = Json::array(), keybindings = Json::array(); + Json menus = contributes.contains("menus") ? contributes["menus"] : Json::object(); + Json palette = menus.contains("commandPalette") ? menus["commandPalette"] : Json::array(); + for (const auto& c : spec.commands["commands"]) { + if (!offered_in(c, "vscode")) continue; + const auto id = c.value("id", ""); + Json cmd{{"command", id}, {"title", std::format("%command.{}.title%", id)}, {"category", "%category%"}}; + if (c.contains("icon") && c["icon"].contains("vscode")) cmd["icon"] = c["icon"]["vscode"]; + commands.push_back(cmd); + if (c.contains("keybinding")) { + Json k{{"command", id}, {"key", c["keybinding"].value("key", "")}}; + if (c["keybinding"].contains("mac")) k["mac"] = c["keybinding"]["mac"]; + if (c.contains("when")) k["when"] = c["when"]; + keybindings.push_back(k); + } + if (c.contains("menus")) + for (const auto& m : c["menus"]) { + Json entry{{"command", id}}; + if (m.contains("group")) entry["group"] = m["group"]; + if (m.contains("when")) entry["when"] = m["when"]; + menus[m.value("menu", "")].push_back(entry); + } + if (!c.value("palette", true)) palette.push_back(Json{{"command", id}, {"when", "false"}}); + else if (c.contains("when")) palette.push_back(Json{{"command", id}, {"when", c["when"]}}); + } + menus["commandPalette"] = palette; + contributes["commands"] = commands; + contributes["keybindings"] = keybindings; + contributes["menus"] = menus; + + // One configuration object; a setting's order is its group's order, then its own. + std::map groupOrder; + for (const auto& g : spec.settings["groups"]) groupOrder[g.value("id", "")] = g.value("order", 0); + Json properties = Json::object(); + for (const auto& s : spec.settings["settings"]) { + const auto key = s.value("key", ""); + Json p{{"type", s.value("type", "string")}, {"default", s.contains("default") ? s["default"] : Json(nullptr)}}; + if (s.contains("enum")) p["enum"] = s["enum"]; + if (s.value("type", "") == "array") p["items"] = Json{{"type", "string"}}; + if (s.contains("minimum")) p["minimum"] = s["minimum"]; + if (s.contains("maximum")) p["maximum"] = s["maximum"]; + p["scope"] = s.value("scope", "resource"); + p["order"] = groupOrder[s.value("group", "")] * 1000 + s.value("order", 0); + p["description"] = std::format("%{}.title%", key); + p["markdownDescription"] = std::format("%{}.description%", key); + if (s.value("deprecated", false)) p["markdownDeprecationMessage"] = std::format("%{}.deprecationMessage%", key); + if (s.value("tier", "") == "advanced") p["tags"] = Json::array({"advanced"}); + properties[key] = p; + } + contributes["configuration"] = Json{{"title", "%mcpp.configuration.title%"}, {"properties", properties}}; +} + +void copy_tree(const fs::path& from, const fs::path& to, std::span skip = {}) { + std::error_code ec; + if (!fs::exists(from, ec)) return; + for (fs::recursive_directory_iterator it(from, ec), end; !ec && it != end; it.increment(ec)) { + const auto rel = fs::relative(it->path(), from, ec); + const auto relText = rel.generic_string(); + if (std::ranges::any_of(skip, [&](std::string_view s) { return relText == s || relText.starts_with(std::string(s) + "/"); })) { + if (it->is_directory(ec)) it.disable_recursion_pending(); + continue; + } + if (it->is_directory(ec)) { fs::create_directories(to / rel, ec); continue; } + fs::create_directories((to / rel).parent_path(), ec); + fs::copy_file(it->path(), to / rel, fs::copy_options::overwrite_existing, ec); + if (ec) throw std::runtime_error(std::format("copying {}: {}", it->path().generic_string(), ec.message())); + } +} + +int gen_vscode(std::span args) { + const auto root = repo(); + const auto out = fs::path(option(args, "--out").value_or((root / "vscode" / "dist" / "extension").string())); + const auto spec = load_spec(root); + auto pkg = read_json(root / "vscode" / "package.json"); + vscode_contributes(spec, pkg["contributes"]); + // npm's own fields stay in the development manifest. + pkg.erase("scripts"); + pkg.erase("devDependencies"); + spit(out / "package.json", pkg.dump(2) + "\n"); + spit(out / "package.nls.json", spec.en.dump(2) + "\n"); + Json zh = spec.en; + for (auto it = spec.zh.begin(); it != spec.zh.end(); ++it) zh[it.key()] = it.value(); + spit(out / "package.nls.zh-cn.json", zh.dump(2) + "\n"); + if (flag(args, "--stage")) { + copy_tree(root / "vscode" / "out" / "src", out / "out" / "src"); + copy_tree(root / "vscode" / "media", out / "media"); + copy_tree(root / "vscode" / "syntaxes", out / "syntaxes"); + static constexpr std::array webuiSkip{"tests", "tsconfig.json"}; + copy_tree(root / "webui", out / "webui", webuiSkip); + for (const auto* f : {"README.md", "CHANGELOG.md", ".vscodeignore"}) + if (fs::exists(root / "vscode" / f)) fs::copy_file(root / "vscode" / f, out / f, fs::copy_options::overwrite_existing); + fs::copy_file(root / "LICENSE", out / "LICENSE.txt", fs::copy_options::overwrite_existing); + if (auto backends = option(args, "--backends")) copy_tree(*backends, out / "bin"); + } + std::println("vscode declarations in {}", out.generic_string()); + return 0; +} + +// A .properties value: ASCII, everything else as \uXXXX (UTF-16 units), and the format's own +// characters escaped. +std::string properties_escape(std::string_view s) { + std::string out; + std::size_t i = 0; + while (i < s.size()) { + unsigned char c = static_cast(s[i]); + char32_t cp = c; + int n = 1; + if (c >= 0xF0) { cp = c & 0x07; n = 4; } + else if (c >= 0xE0) { cp = c & 0x0F; n = 3; } + else if (c >= 0xC0) { cp = c & 0x1F; n = 2; } + for (int k = 1; k < n && i + k < s.size(); ++k) cp = (cp << 6) | (static_cast(s[i + k]) & 0x3F); + i += n; + if (cp == '\\') out += "\\\\"; + else if (cp == '\n') out += "\\n"; + else if (cp == '=' || cp == ':' || cp == '#' || cp == '!') { out += '\\'; out += static_cast(cp); } + else if (cp < 0x80) out += static_cast(cp); + else if (cp < 0x10000) out += std::format("\\u{:04x}", static_cast(cp)); + else { + const char32_t v = cp - 0x10000; + out += std::format("\\u{:04x}\\u{:04x}", static_cast(0xD800 + (v >> 10)), static_cast(0xDC00 + (v & 0x3FF))); + } + } + return out; +} + +std::string xml_escape(std::string_view s) { + std::string out; + for (char c : s) { + if (c == '&') out += "&"; + else if (c == '<') out += "<"; + else if (c == '>') out += ">"; + else if (c == '"') out += """; + else out += c; + } + return out; +} + +int gen_jetbrains(std::span args) { + const auto root = repo(); + const auto out = fs::path(option(args, "--out").value_or((root / "jetbrains" / "build" / "generated" / "mcpp-ide").string())); + const auto spec = load_spec(root); + // The actions: one group per spec group under Tools | mcpp, every command one action of the same + // class, which reads what it does from the backend's command table by its id. JetBrains keeps its + // own keymap (the VS Code chords are taken there: Ctrl+Alt+B is Go to Implementation), so no + // shortcut is declared. + std::string xml = "\n\n \n"; + xml += " \n"; + xml += " \n"; + std::map> byGroup; + for (const auto& c : spec.commands["commands"]) + if (offered_in(c, "jetbrains") && !c.value("deprecated", false)) byGroup[c.value("group", "")].push_back(&c); + for (const auto& g : spec.commands["groups"]) { + const auto gid = g.value("id", ""); + if (!byGroup.contains(gid)) continue; + xml += std::format(" \n", gid); + for (const auto* c : byGroup[gid]) { + const auto id = c->value("id", ""); + xml += std::format(" contains("icon") && (*c)["icon"].contains("jetbrains")) xml += std::format(" icon=\"{}\"", xml_escape((*c)["icon"]["jetbrains"].get())); + xml += "/>\n"; + } + xml += " \n"; + } + xml += " \n \n\n"; + spit(out / "META-INF" / "mcpp-actions.xml", xml); + + // The bundles: the actions' texts, the groups', and every editor string under its own key. + auto bundle = [&](const Json& strings) { + std::string text = "# Generated by mcpp-ide-dev gen jetbrains from spec/i18n.\n"; + std::vector> rows; + for (const auto& c : spec.commands["commands"]) { + if (!offered_in(c, "jetbrains")) continue; + const auto id = c.value("id", ""); + const auto key = std::format("command.{}.title", id); + const auto title = strings.contains(key) ? strings[key].get() : spec.en.value(key, id); + rows.push_back({std::format("action.{}.text", id), title}); + } + for (const auto& g : spec.commands["groups"]) { + const auto key = g.value("title", ""); + const auto title = strings.contains(key) ? strings[key].get() : spec.en.value(key, key); + rows.push_back({std::format("group.mcpp.Menu.{}.text", g.value("id", "")), title}); + } + rows.push_back({"group.mcpp.Menu.text", "mcpp"}); + for (auto it = strings.begin(); it != strings.end(); ++it) + if (it->is_string()) rows.push_back({it.key(), it->get()}); + std::ranges::sort(rows); + rows.erase(std::unique(rows.begin(), rows.end(), [](const auto& a, const auto& b) { return a.first == b.first; }), rows.end()); + for (const auto& [k, v] : rows) text += std::format("{}={}\n", properties_escape(k), properties_escape(v)); + return text; + }; + Json zh = spec.en; + for (auto it = spec.zh.begin(); it != spec.zh.end(); ++it) zh[it.key()] = it.value(); + spit(out / "messages" / "McppClionBundle.properties", bundle(spec.en)); + spit(out / "messages" / "McppClionBundle_zh_CN.properties", bundle(zh)); + std::println("jetbrains declarations in {}", out.generic_string()); + return 0; +} + +// ── check-i18n ────────────────────────────────────────────────────────────── + +// The first argument of every `t("…")` / `t('…')` / `t(`…`)` in a source: a runtime string. +std::vector runtime_strings(std::string_view text) { + std::vector out; + for (std::size_t pos = 0; (pos = text.find("t(", pos)) != std::string_view::npos; pos += 2) { + if (pos > 0) { + const char before = text[pos - 1]; + if (std::isalnum(static_cast(before)) || before == '_' || before == '.') continue; + } + std::size_t i = pos + 2; + while (i < text.size() && (text[i] == ' ' || text[i] == '\n')) ++i; + if (i >= text.size()) break; + const char quote = text[i]; + if (quote != '"' && quote != '\'' && quote != '`') continue; + std::string s; + bool closed = false; + for (++i; i < text.size(); ++i) { + if (text[i] == '\\' && i + 1 < text.size()) { + const char n = text[++i]; + s += n == 'n' ? '\n' : n; + continue; + } + if (text[i] == quote) { closed = true; break; } + if (quote == '`' && text[i] == '$' && i + 1 < text.size() && text[i + 1] == '{') { closed = false; break; } + s += text[i]; + } + if (closed && !s.empty()) out.push_back(std::move(s)); + } + return out; +} + +int check_i18n(std::span) { + const auto root = repo(); + const auto zh = read_json(root / "spec" / "i18n" / "runtime.zh-cn.json"); + std::set missing; + std::size_t seen = 0; + const std::array>, 4> trees{{ + {root / "src", {".cppm", ".cpp"}}, + {root / "vscode" / "src", {".ts"}}, + {root / "webui", {".js"}}, + {root / "jetbrains" / "src" / "main" / "kotlin", {".kt"}}, + }}; + std::error_code ec; + for (const auto& [dir, exts] : trees) + for (fs::recursive_directory_iterator it(dir, ec), end; !ec && it != end; it.increment(ec)) { + if (!it->is_regular_file(ec)) continue; + const auto ext = it->path().extension().string(); + if (std::ranges::find(exts, ext) == exts.end()) continue; + if (it->path().generic_string().find("/node_modules/") != std::string::npos) continue; + // This program's own scanner reads like a call. + if (it->path().filename() == "dev.cpp") continue; + auto found = runtime_strings(slurp(it->path())); + // A cleanup plan's texts are translated where they are shown (policy.cppm's `titleKey`). + for (std::string_view key : {"titleKey = \"", "detailKey = \""}) { + const auto text = slurp(it->path()); + for (auto pos = text.find(key); pos != std::string::npos; pos = text.find(key, pos + 1)) { + const auto start = pos + key.size(); + const auto end = text.find('"', start); + if (end != std::string::npos) found.push_back(text.substr(start, end - start)); + } + } + for (const auto& s : found) { + ++seen; + if (!zh.contains(s)) missing.insert(s); + } + } + const auto en = read_json(root / "spec" / "i18n" / "manifest.en.json"); + const auto zhm = read_json(root / "spec" / "i18n" / "manifest.zh-cn.json"); + std::vector missingEditor; + for (auto it = en.begin(); it != en.end(); ++it) if (!zhm.contains(it.key())) missingEditor.push_back(it.key()); + for (const auto& s : missing) std::println("runtime string without zh-cn: {}", Json(s).dump()); + for (const auto& k : missingEditor) std::println("editor string without zh-cn: {}", k); + std::println("{} runtime strings read; {} without a translation; {} editor strings without one", seen, missing.size(), + missingEditor.size()); + return missing.empty() && missingEditor.empty() ? 0 : 1; +} + +} // namespace + +int main(int argc, char** argv) { + std::vector args(argv + 1, argv + argc); + try { + if (args.empty() || args[0] == "--help") { + std::println("mcpp-ide-dev capture | gen vscode|jetbrains --out DIR | check-i18n"); + return args.empty() ? 2 : 0; + } + const std::span rest(args.begin() + 1, args.end()); + if (args[0] == "capture") return capture(rest); + if (args[0] == "check-i18n") return check_i18n(rest); + if (args[0] == "gen" && !rest.empty()) { + const std::span more(rest.begin() + 1, rest.end()); + if (rest[0] == "vscode") return gen_vscode(more); + if (rest[0] == "jetbrains") return gen_jetbrains(more); + } + std::println(std::cerr, "mcpp-ide-dev: unknown command (capture, gen vscode|jetbrains, check-i18n)"); + return 2; + } catch (const std::exception& e) { + std::println(std::cerr, "mcpp-ide-dev: {}", e.what()); + return 1; + } +} diff --git a/src/bin/mockmcpp.cpp b/src/bin/mockmcpp.cpp index f3afe77..20c0538 100644 --- a/src/bin/mockmcpp.cpp +++ b/src/bin/mockmcpp.cpp @@ -1,9 +1,9 @@ // A stand-in for mcpp in the tests: answers mcpp's control contract from the // golden fixtures (protocol/fixtures, captured from a real mcpp by -// tools/capture-fixtures.sh). `@ROOT@` in a fixture becomes the directory the +// `mcpp-ide-dev capture`). `@ROOT@` in a fixture becomes the directory the // command runs in, `@HOME@` the home. // -// MCPPIDE_FIXTURES the fixtures directory (required) +// MCPPIDE_FIXTURES the fixtures directory (default: the repository's protocol/fixtures) // MOCK_MCPP_FAIL "build": the build fails with the compiler's diagnostic; // "manifest": it fails on the manifest // MOCK_MCPP_SLOW_MS the build waits this long before it ends, so a test can @@ -29,8 +29,20 @@ std::string replace_all(std::string s, std::string_view from, std::string_view t return s; } +// The fixtures: MCPPIDE_FIXTURES, else the repository's, found above this program (it is built +// under target/ of the repository). +std::filesystem::path fixtures_dir() { + if (auto d = env("MCPPIDE_FIXTURES"); !d.empty()) return d; + std::error_code ec; + for (auto d = mcpplibs::os::env::image().value_or(std::filesystem::path{}).parent_path(); !d.empty(); d = d.parent_path()) { + if (std::filesystem::is_directory(d / "protocol" / "fixtures", ec)) return d / "protocol" / "fixtures"; + if (d == d.parent_path()) break; + } + return {}; +} + std::string fixture(std::string_view name) { - const auto dir = env("MCPPIDE_FIXTURES"); + const auto dir = fixtures_dir(); auto text = slurp(std::filesystem::path(dir) / name); std::error_code ec; text = replace_all(std::move(text), "@ROOT@", std::filesystem::current_path(ec).generic_string()); @@ -89,7 +101,7 @@ int main(int argc, char** argv) { if (first(0) == "--version") { std::cout << fixture("version.txt"); return 0; } if (first(0) == "--protocol-version") { std::cout << fixture("protocol-version.json"); return 0; } if (first(0) == "build") return build(has("--message-format")); - if (first(0) == "test") { std::cout << fixture("test.ndjson"); return 0; } + if (first(0) == "test") { std::cout << fixture(has("--list") ? "test-list.ndjson" : "test.ndjson"); return 0; } if (first(0) == "run" && has("--print-launch")) { std::cout << fixture("launch.json"); return 0; } if (first(0) == "search") { std::cout << fixture("search.json"); return 0; } if (first(0) == "index" && first(1) == "list") { std::cout << fixture("index-list.json"); return 0; } diff --git a/src/languageservice.cppm b/src/languageservice.cppm new file mode 100644 index 0000000..9b9e391 --- /dev/null +++ b/src/languageservice.cppm @@ -0,0 +1,134 @@ +// The language service beside this backend: mcppls. mcpp-ide registers no language service of its +// own (design 2026-10-28 §11.2); every editor feature of a C++ file is mcppls's, and the panels say +// which mcppls answers and whether it is new enough. +// +// THE HANDSHAKE IS A VERSION, READ FROM THE PROGRAM. `mcppls --version` prints the version (bare, or +// after the program's name). mcppls 0.0.18 is the first release that reads mcpp's result record +// (`target/.last-result.json`, mcpp docs/50 §5.2) and refreshes after any build -- one started here, +// in a terminal or by an agent -- so a build through mcpp-ide needs nothing forwarded to it. An older +// mcppls is reported with what to do, never degraded around in silence. +export module mcppide.languageservice; + +import std; +import nlohmann.json; +import mcpplibs.os; +import mcppide.mcpp; + +export namespace mcppide::languageservice { + +using Json = nlohmann::json; + +// The first mcppls that reads the result record. +inline constexpr std::string_view kRequired = "0.0.18"; + +enum class State { ok, outdated, missing, unreadable }; +std::string_view state_name(State s); + +struct Status { + State state = State::missing; + std::filesystem::path program; // the mcppls that answered (empty when none was found) + std::string source; // "editor" (a path the adapter named) | "PATH" | "xlings" | "payload" + std::string version; // as it printed it + std::string detail; // why the version could not be read +}; + +// The version in `mcppls --version`'s output: the first word that starts with a digit. +std::string version_in(std::string_view output); + +// The places to look, in order: what the adapter knows (the mcppls extension's or plugin's own +// server), PATH, xlings, and the payload the mcppls CLion plugin installs. +std::vector> candidates(const std::vector& fromEditor); + +// Finds mcppls among the candidates and reads its version. +Status probe(const std::vector& fromEditor); +// The status for an mcppls at `program` whose `--version` printed `output` (the tests). +Status classify(const std::filesystem::path& program, std::string source, std::string_view output); + +} // namespace mcppide::languageservice + +namespace mcppide::languageservice { + +std::string_view state_name(State s) { + switch (s) { + case State::ok: return "ok"; + case State::outdated: return "outdated"; + case State::missing: return "missing"; + case State::unreadable: return "unreadable"; + } + return "missing"; +} + +std::string version_in(std::string_view output) { + std::string word; + auto take = [&]() -> std::optional { + if (!word.empty() && std::isdigit(static_cast(word.front()))) { + while (!word.empty() && !std::isdigit(static_cast(word.back()))) word.pop_back(); + return word; + } + word.clear(); + return std::nullopt; + }; + for (char c : output) { + if (c == ' ' || c == '\t' || c == '\r' || c == '\n') { + if (auto v = take()) return *v; + continue; + } + word.push_back(c); + } + if (auto v = take()) return *v; + return {}; +} + +std::vector> candidates(const std::vector& fromEditor) { + std::vector> out; + for (const auto& p : fromEditor) if (!p.empty()) out.push_back({std::filesystem::path(p), "editor"}); + if (auto found = mcpplibs::os::env::find_executable("mcppls")) out.push_back({*found, "PATH"}); + const auto exe = std::string("mcppls") + std::string(mcpplibs::os::conventions().exe_suffix); + if (auto xh = mcpplibs::os::env::get("XLINGS_HOME")) + out.push_back({std::filesystem::path(*xh) / "subos" / "current" / "bin" / exe, "xlings"}); + if (auto home = mcpplibs::os::dirs::home()) { + out.push_back({*home / ".xlings" / "subos" / "current" / "bin" / exe, "xlings"}); + out.push_back({*home / ".xlings" / "subos" / "default" / "bin" / exe, "xlings"}); + } + // The mcppls CLion plugin's `--install` puts the server at `/mcppls/payload`. + if (auto data = mcpplibs::os::dirs::data()) out.push_back({*data / "mcppls" / "payload" / "bin" / exe, "payload"}); + return out; +} + +Status classify(const std::filesystem::path& program, std::string source, std::string_view output) { + Status s; + s.program = program; + s.source = std::move(source); + s.version = version_in(output); + if (s.version.empty()) { + s.state = State::unreadable; + s.detail = std::format("`{} --version` printed no version", program.filename().string()); + return s; + } + s.state = mcpp::compare_versions(s.version, kRequired) >= 0 ? State::ok : State::outdated; + return s; +} + +Status probe(const std::vector& fromEditor) { + std::error_code ec; + for (const auto& [program, source] : candidates(fromEditor)) { + if (!std::filesystem::is_regular_file(program, ec)) continue; + mcpplibs::os::process::spawn_options o; + o.program = program; + o.args = {"--version"}; + o.in = mcpplibs::os::process::stdio::null; + auto r = mcpplibs::os::process::run(o); + if (!r) { + Status s; + s.state = State::unreadable; + s.program = program; + s.source = source; + s.detail = r.error().message(); + return s; + } + return classify(program, source, r->out); + } + return Status{}; +} + +} // namespace mcppide::languageservice diff --git a/src/mcpp.cppm b/src/mcpp.cppm index e207a85..b8c5df9 100644 --- a/src/mcpp.cppm +++ b/src/mcpp.cppm @@ -75,6 +75,15 @@ public: }; std::expected envelope(const RunOptions& o) const; + // Runs a command whose standard output is NDJSON (`mcpp test --list --message-format json`): + // every line that is a JSON document, in order. + struct RecordsResult { + int exitCode = -1; + std::vector records; + std::string narration; + }; + std::expected records(const RunOptions& o) const; + private: std::filesystem::path program_; Protocol protocol_; @@ -225,6 +234,27 @@ std::expected Client::envelope(const RunOpt return out; } +std::expected Client::records(const RunOptions& o) const { + auto r = mcpplibs::os::process::run(spawn_options(o)); + if (!r) return std::unexpected(r.error().message()); + RecordsResult out; + out.exitCode = r->status.shell_code(); + out.narration = std::move(r->err); + std::size_t pos = 0; + while (pos < r->out.size()) { + auto end = r->out.find('\n', pos); + if (end == std::string::npos) end = r->out.size(); + auto line = std::string_view(r->out).substr(pos, end - pos); + if (!line.empty() && line.back() == '\r') line.remove_suffix(1); + if (!line.empty()) { + auto doc = Json::parse(line, nullptr, false); + if (!doc.is_discarded()) out.records.push_back(std::move(doc)); + } + pos = end + 1; + } + return out; +} + Json diagnostics_of(const Json& envelope) { Json out = Json::array(); if (!envelope.is_object() || !envelope.contains("diagnostics") || !envelope["diagnostics"].is_array()) return out; diff --git a/src/schema.cppm b/src/schema.cppm new file mode 100644 index 0000000..7c96ff8 --- /dev/null +++ b/src/schema.cppm @@ -0,0 +1,110 @@ +// The part of JSON Schema (2020-12) protocol/*.schema.json uses: `type` (one or a list), `enum`, +// `const`, `properties`, `required`, `additionalProperties`, `items`, `minItems`, `minimum`, `allOf`, +// `anyOf`, `oneOf` and `$ref` into the document's own `$defs`. Enough for the backend's tests to hold +// the golden fixtures to the contract the backend reads, and the backend's answers to the protocol +// the adapters read; a keyword outside this list is ignored, never guessed at. +export module mcppide.schema; + +import std; +import nlohmann.json; + +export namespace mcppide::schema { + +using Json = nlohmann::json; + +// The problems of `value` against `schema` (whose `$ref`s resolve in `root`), each one line with the +// JSON pointer of the value it is about; empty when the value conforms. +std::vector validate(const Json& value, const Json& schema, const Json& root); + +} // namespace mcppide::schema + +namespace mcppide::schema { + +namespace { + +bool has_type(const Json& v, std::string_view type) { + if (type == "object") return v.is_object(); + if (type == "array") return v.is_array(); + if (type == "string") return v.is_string(); + if (type == "integer") return v.is_number_integer(); + if (type == "number") return v.is_number(); + if (type == "boolean") return v.is_boolean(); + if (type == "null") return v.is_null(); + return false; +} + +const Json* resolve(const Json& root, std::string_view ref) { + constexpr std::string_view prefix = "#/$defs/"; + if (!ref.starts_with(prefix)) return nullptr; + const auto name = std::string(ref.substr(prefix.size())); + if (!root.contains("$defs") || !root["$defs"].contains(name)) return nullptr; + return &root["$defs"][name]; +} + +void check(const Json& v, const Json& s, const Json& root, const std::string& at, std::vector& out, int depth) { + if (depth > 64) { out.push_back(std::format("{}: the schema recurses too deep", at)); return; } + if (s.is_boolean()) { + if (!s.get()) out.push_back(std::format("{}: no value is allowed here", at.empty() ? "/" : at)); + return; + } + if (!s.is_object()) return; + const auto where = at.empty() ? std::string("/") : at; + if (s.contains("$ref")) { + const auto* target = resolve(root, s["$ref"].get()); + if (!target) out.push_back(std::format("{}: unresolved $ref {}", where, s["$ref"].get())); + else check(v, *target, root, at, out, depth + 1); + } + if (s.contains("type")) { + bool ok = false; + if (s["type"].is_string()) ok = has_type(v, s["type"].get()); + else for (const auto& t : s["type"]) ok = ok || has_type(v, t.get()); + if (!ok) { out.push_back(std::format("{}: expected {}, found {}", where, s["type"].dump(), v.type_name())); return; } + } + if (s.contains("const") && v != s["const"]) out.push_back(std::format("{}: expected {}, found {}", where, s["const"].dump(), v.dump())); + if (s.contains("enum") && std::ranges::find(s["enum"], v) == s["enum"].end()) + out.push_back(std::format("{}: {} is not one of {}", where, v.dump(), s["enum"].dump())); + if (s.contains("minimum") && v.is_number() && v.get() < s["minimum"].get()) + out.push_back(std::format("{}: {} is below {}", where, v.dump(), s["minimum"].dump())); + if (v.is_object()) { + if (s.contains("required")) + for (const auto& k : s["required"]) + if (!v.contains(k.get())) out.push_back(std::format("{}: missing \"{}\"", where, k.get())); + for (auto it = v.begin(); it != v.end(); ++it) { + const auto path = at + "/" + it.key(); + if (s.contains("properties") && s["properties"].contains(it.key())) check(it.value(), s["properties"][it.key()], root, path, out, depth + 1); + else if (s.contains("additionalProperties")) check(it.value(), s["additionalProperties"], root, path, out, depth + 1); + } + } + if (v.is_array()) { + if (s.contains("minItems") && v.size() < s["minItems"].get()) + out.push_back(std::format("{}: {} items, at least {} expected", where, v.size(), s["minItems"].get())); + if (s.contains("items")) + for (std::size_t i = 0; i < v.size(); ++i) check(v[i], s["items"], root, std::format("{}/{}", at, i), out, depth + 1); + } + if (s.contains("allOf")) for (const auto& sub : s["allOf"]) check(v, sub, root, at, out, depth + 1); + auto matches = [&](const Json& sub) { + std::vector trial; + check(v, sub, root, at, trial, depth + 1); + return trial.empty(); + }; + if (s.contains("anyOf")) { + bool any = false; + for (const auto& sub : s["anyOf"]) if (matches(sub)) { any = true; break; } + if (!any) out.push_back(std::format("{}: matches none of anyOf ({} alternatives)", where, s["anyOf"].size())); + } + if (s.contains("oneOf")) { + int n = 0; + for (const auto& sub : s["oneOf"]) if (matches(sub)) ++n; + if (n != 1) out.push_back(std::format("{}: matches {} of oneOf, exactly one expected", where, n)); + } +} + +} // namespace + +std::vector validate(const Json& value, const Json& schema, const Json& root) { + std::vector out; + check(value, schema, root, "", out, 0); + return out; +} + +} // namespace mcppide::schema diff --git a/src/server.cppm b/src/server.cppm index 07f6bb5..f9e8bf5 100644 --- a/src/server.cppm +++ b/src/server.cppm @@ -3,9 +3,10 @@ // the methods of protocol/protocol.schema.json. // // THE ADAPTER DECIDES NOTHING. Which argv a build runs, how much confirmation a -// clean needs, what a cache panel shows, what a setting may hold: answered -// here, so VS Code and CLion behave alike and an agent reading the backend's -// log sees the same reasons a person sees in the editor. +// clean needs, what a cache panel shows, what a setting may hold, which +// commands an editor offers and what a test record means: answered here, so VS +// Code and CLion behave alike and an agent reading the backend's log sees the +// same reasons a person sees in the editor. export module mcppide.server; import std; @@ -19,6 +20,8 @@ import mcppide.policy; import mcppide.settings; import mcppide.i18n; import mcppide.manifest; +import mcppide.spec; +import mcppide.languageservice; import mcpplibs.os; export namespace mcppide::server { @@ -28,6 +31,25 @@ using Json = nlohmann::json; inline constexpr std::string_view kVersion = "0.1.0"; inline constexpr int kProtocol = 1; +// The methods `install` registers, for the protocol schema's test: a method +// here and not in protocol/protocol.schema.json (or the other way) fails it. +inline constexpr std::array kMethods = { + "initialize", "settings/update", "settings/registry", "settings/preset", "i18n/bundle", + "selfCheck", "commands/list", "menu/quick", "languageService/status", + "projects/list", "projects/forFile", "project/summary", "project/new", "result/last", + "job/start", "job/cancel", "job/list", "run/launch", "debug/configuration", "test/list", + "library/search", "library/indexes", "library/add", "library/updateIndex", + "toolchains/list", "toolchains/install", "toolchains/setDefault", "targets/list", + "cache/inventory", "cache/plan", "cache/apply", "graph/packages", "graph/modules", + "pack/formats", "pack/start", "manifest/check", "toml/complete", "toml/hover", "toml/symbols", + "buildscript/complete", "shutdown", "exit"}; + +// The notifications the backend sends. +inline constexpr std::array kNotifications = { + "job/started", "job/output", "job/plan", "job/progress", "job/diagnostic", "job/artifact", "job/record", + "job/finished", "test/result", "test/summary", "result/changed", "manifest/changed", + "manifest/diagnostics"}; + class Session { public: explicit Session(rpc::Server& server); @@ -49,7 +71,13 @@ private: Result cache_apply(const Json& p); Result graph(const Json& p, bool modules); Result project_summary(const Json& p); + Result project_new(const Json& p); Result manifest_check(const Json& p); + Result language_service(const Json& p); + Result targets(const Json& p); + Result commands(const Json& p) const; + Result quick_menu(const Json& p); + Result test_list(const Json& p); std::expected query(const std::filesystem::path& cwd, std::vector args) const; @@ -57,8 +85,13 @@ private: std::vector deny() const; std::string client_label() const; std::string t(std::string_view key, const std::vector& args = {}) const; + Json setting(std::string_view key) const; + // `--target ` for a request: its own `target`, else `mcpp.build.target`; nothing for the host. + std::vector target_args(const Json& p) const; + std::filesystem::path any_root(const Json& p) const; void locate_mcpp(); void on_changed(const std::filesystem::path& root, std::string_view what, const Json& detail); + void on_record(std::string_view jobId, const Json& record); rpc::Server& rpc_; mutable std::mutex mutex_; @@ -67,8 +100,11 @@ private: std::string mcppError_; Json settings_ = Json::object(); bool trusted_ = true; + mutable std::mutex localeMutex_; std::string locale_ = "en"; std::string clientName_ = "mcpp-ide"; + std::string editor_ = "vscode"; + std::vector mcpplsCandidates_; std::vector folders_; std::unique_ptr jobs_; std::unique_ptr watcher_; @@ -77,6 +113,10 @@ private: Json searchCache_; std::chrono::steady_clock::time_point searchAt_{}; std::map buildDatabases_; + // The project and kind of each job, for the notifications its records become. + std::map, std::less<>> jobOf_; + // The configuration (and platforms) the last plan of each project named. + std::map plans_; }; } // namespace mcppide::server @@ -97,6 +137,15 @@ std::vector strings_of(const Json& v) { if (v.is_array()) for (const auto& x : v) if (x.is_string()) out.push_back(x.get()); return out; } +// A command's place in an editor: `editors` lists the editors that offer it (all, when absent); a +// forward to mcppls's own commands exists only where mcppls has commands to forward to (VS Code). +bool offered_in(const Json& c, std::string_view editor) { + if (c.contains("editors") && c["editors"].is_array()) + return std::ranges::any_of(c["editors"], [&](const Json& e) { return e.is_string() && e.get() == editor; }); + const auto kind = c.contains("action") ? c["action"].value("kind", "") : std::string{}; + if (kind == "forward" || kind == "editor") return editor == "vscode"; + return true; +} } // namespace Session::Session(rpc::Server& server) : rpc_(server) { @@ -104,15 +153,32 @@ Session::Session(rpc::Server& server) : rpc_(server) { .narration = [this](std::string_view id, std::string_view text) { rpc_.notify("job/output", Json{{"jobId", id}, {"text", text}}); }, - .record = [this](std::string_view id, const Json& record) { - rpc_.notify("job/record", Json{{"jobId", id}, {"record", record}}); - }, + .record = [this](std::string_view id, const Json& record) { on_record(id, record); }, .finished = [this](std::string_view id, const Json& summary) { Json s = summary; s["jobId"] = id; + // The envelope's own diagnostics and artifacts, as the adapters consume them. + if (summary.contains("envelope")) { + s["diagnostics"] = mcpp::diagnostics_of(summary["envelope"]); + const auto& env = summary["envelope"]; + if (env.is_object() && env.contains("data") && env["data"].is_object() && env["data"].contains("artifacts")) + s["artifacts"] = env["data"]["artifacts"]; + } + { + std::lock_guard lock(mutex_); + if (auto it = jobOf_.find(id); it != jobOf_.end()) { + s["root"] = it->second.first.generic_string(); + s["kind"] = it->second.second; + jobOf_.erase(it); + } + } rpc_.notify("job/finished", s); }, .started = [this](std::string_view id, const Json& started) { + { + std::lock_guard lock(mutex_); + jobOf_[std::string(id)] = {std::filesystem::path(started.value("root", "")), started.value("kind", "")}; + } Json s = started; s["jobId"] = id; rpc_.notify("job/started", s); @@ -127,8 +193,37 @@ Session::~Session() { jobs_.reset(); } +// The locale has a lock of its own: a message is often composed while `mutex_` is held. std::string Session::t(std::string_view key, const std::vector& args) const { - return i18n::translate(key, locale_, args); + std::string locale; + { + std::lock_guard lock(localeMutex_); + locale = locale_; + } + return i18n::translate(key, locale, args); +} + +Json Session::setting(std::string_view key) const { + std::lock_guard lock(mutex_); + if (auto it = settings_.find(std::string(key)); it != settings_.end()) return *it; + if (auto* s = settings::find(key)) return settings::default_of(*s); + return nullptr; +} + +std::vector Session::target_args(const Json& p) const { + std::string target = p.contains("target") && p["target"].is_string() ? p["target"].get() : std::string{}; + if (!p.contains("target")) { + const auto chosen = setting("mcpp.build.target"); + if (chosen.is_string()) target = chosen.get(); + } + if (target.empty()) return {}; + return {"--target", target}; +} + +std::filesystem::path Session::any_root(const Json& p) const { + if (auto r = root_of(p); !r.empty()) return r; + std::lock_guard lock(mutex_); + return folders_.empty() ? std::filesystem::current_path() : folders_.front(); } std::vector Session::deny() const { @@ -185,6 +280,41 @@ void Session::on_changed(const std::filesystem::path& root, std::string_view wha if (checked) rpc_.notify("manifest/diagnostics", *checked); } +// A record of a job's stream becomes the notification its meaning names: the plan (with the +// platforms mcpp reports, kept per project for the panels), progress, a located diagnostic, a test's +// result, the tests' summary. What has no meaning here goes out as it came (`job/record`). +void Session::on_record(std::string_view jobId, const Json& record) { + auto n = views::stream_record(record); + std::string root; + { + std::lock_guard lock(mutex_); + if (auto it = jobOf_.find(jobId); it != jobOf_.end()) root = it->second.first.generic_string(); + } + n["jobId"] = jobId; + n["root"] = root; + const auto type = n.value("type", "other"); + if (type == "plan") { + { + std::lock_guard lock(mutex_); + plans_[std::filesystem::path(root)] = n; + } + rpc_.notify("job/plan", n); + } else if (type == "progress") { + rpc_.notify("job/progress", n); + } else if (type == "diagnostic") { + rpc_.notify("job/diagnostic", n); + } else if (type == "artifact") { + rpc_.notify("job/artifact", n); + } else if (type == "test") { + rpc_.notify("test/result", n); + } else if (type == "summary") { + rpc_.notify("test/summary", n); + } else if (!(record.is_object() && record.contains("schemaVersion") && record.value("kind", "") != "mcpp.event")) { + // The envelope that closes a stream reaches the adapter in `job/finished`. + rpc_.notify("job/record", n); + } +} + std::expected Session::query(const std::filesystem::path& cwd, std::vector args) const { mcpp::Client client; @@ -246,6 +376,14 @@ Json Session::self_check() { {mcppPart["version"].get(), std::string(mcpp::kContractFloor)})); else add("contract", "ok", t("the control contract is available")); } + std::vector candidates; + { + std::lock_guard lock(mutex_); + candidates = mcpplsCandidates_; + } + auto ls = language_service(Json{{"candidates", candidates}}); + if (ls) add("languageService", (*ls)["state"] == "ok" ? "ok" : (*ls)["state"] == "missing" ? "error" : "warning", + (*ls)["message"].get()); if (auto xlings = mcpplibs::os::env::find_executable("xlings")) add("xlings", "ok", t("xlings at {0}", {xlings->generic_string()})); else add("xlings", "info", t("xlings is not on PATH; mcpp uses the one it bundles")); { @@ -253,7 +391,10 @@ Json Session::self_check() { add("trust", trusted_ ? "ok" : "info", trusted_ ? t("the workspace is trusted") : t("the workspace is not trusted: mcpp runs with effects denied")); } - return Json{{"backend", Json{{"version", kVersion}, {"protocol", kProtocol}}}, {"mcpp", mcppPart}, {"checks", checks}}; + return Json{{"backend", Json{{"version", kVersion}, {"protocol", kProtocol}}}, + {"mcpp", mcppPart}, + {"languageService", ls ? *ls : Json(nullptr)}, + {"checks", checks}}; } std::expected Session::initialize(const Json& p) { @@ -264,11 +405,17 @@ std::expected Session::initialize(const Json& p) { const auto version = p["client"].value("version", ""); clientName_ = std::format("mcpp-ide/{} ({}{}{})", kVersion, name, version.empty() ? "" : " ", version); } - locale_ = i18n::normalize_locale(p.value("locale", "en")); + editor_ = p.value("editor", "vscode"); + { + std::lock_guard localeLock(localeMutex_); + locale_ = i18n::normalize_locale(p.value("locale", "en")); + } trusted_ = p.value("trusted", true); settings_ = settings::resolve(p.contains("settings") ? p["settings"] : Json::object())["values"]; folders_.clear(); for (const auto& f : strings_of(p.value("workspaceFolders", Json::array()))) folders_.emplace_back(f); + if (p.contains("languageService") && p["languageService"].is_object()) + mcpplsCandidates_ = strings_of(p["languageService"].value("candidates", Json::array())); } locate_mcpp(); Json found = Json::array(); @@ -282,10 +429,12 @@ std::expected Session::initialize(const Json& p) { return Json{{"server", Json{{"name", "mcpp-ide"}, {"version", kVersion}}}, {"protocol", kProtocol}, {"mcpp", check["mcpp"]}, + {"languageService", check["languageService"]}, {"checks", check["checks"]}, {"projects", found}, - {"capabilities", Json::array({"jobs", "results", "launch", "debug", "library", "toolchains", "cache", - "graphs", "pack", "settings", "i18n", "manifest", "toml", "buildscript"})}}; + {"capabilities", Json::array({"jobs", "results", "launch", "debug", "tests", "library", "toolchains", + "targets", "platforms", "cache", "graphs", "pack", "settings", "i18n", + "commands", "manifest", "toml", "buildscript", "languageService"})}}; } std::expected Session::update_settings(const Json& p) { @@ -296,7 +445,10 @@ std::expected Session::update_settings(const Json& p) { before = settings_.value("mcpp.path", ""); settings_ = resolved["values"]; if (p.contains("trusted")) trusted_ = p["trusted"].get(); - if (p.contains("locale")) locale_ = i18n::normalize_locale(p["locale"].get()); + if (p.contains("locale")) { + std::lock_guard localeLock(localeMutex_); + locale_ = i18n::normalize_locale(p["locale"].get()); + } } if (before != resolved["values"].value("mcpp.path", "")) locate_mcpp(); return resolved; @@ -320,28 +472,33 @@ std::expected Session::job_start(const Json& p) { r.supersede = p.value("supersede", false); r.color = p.value("color", true); const auto extra = strings_of(p.value("args", Json::array())); - const auto target = p.value("target", ""); - const bool release = p.value("profile", settings_.value("mcpp.build.profile", "dev")) == "release"; + const auto profile = p.value("profile", setting("mcpp.build.profile").is_string() ? setting("mcpp.build.profile").get() : "dev"); + const bool release = profile == "release"; + const auto target = target_args(p); + auto append = [&](const std::vector& v) { r.args.insert(r.args.end(), v.begin(), v.end()); }; switch (*kind) { case jobs::Kind::build: r.args = {"build", "--message-format", "json"}; if (release) r.args.push_back("--release"); - if (!target.empty()) r.args.push_back(target); - for (const auto& a : strings_of(settings_.value("mcpp.task.buildArgs", Json::array()))) r.args.push_back(a); + append(target); + append(strings_of(setting("mcpp.task.buildArgs"))); r.mode = jobs::Mode::ndjson; break; case jobs::Kind::test: r.args = {"test", "--message-format", "json"}; if (release) r.args.push_back("--release"); + append(target); if (p.contains("filter") && p["filter"].is_string() && !p["filter"].get().empty()) r.args.push_back(p["filter"].get()); - for (const auto& a : strings_of(settings_.value("mcpp.task.testArgs", Json::array()))) r.args.push_back(a); + append(strings_of(setting("mcpp.task.testArgs"))); r.mode = jobs::Mode::ndjson; break; case jobs::Kind::pack: { r.args = {"pack"}; if (p.contains("format") && p["format"].is_string()) { r.args.push_back("--format"); r.args.push_back(p["format"]); } + if (p.contains("mode") && p["mode"].is_string()) { r.args.push_back("--mode"); r.args.push_back(p["mode"]); } if (release) r.args.push_back("--release"); + append(target); r.args.push_back("--message-format"); r.args.push_back("json"); r.mode = jobs::Mode::envelope; @@ -353,6 +510,10 @@ std::expected Session::job_start(const Json& p) { const auto spec = p.value("spec", ""); if (spec.empty()) return std::unexpected(invalid("a toolchain job names a spec")); r.args = {"toolchain", "install", spec}; + if (p.contains("target") && p["target"].is_string() && !p["target"].get().empty()) { + r.args.push_back("--target"); + r.args.push_back(p["target"].get()); + } break; } case jobs::Kind::add: { @@ -376,8 +537,10 @@ std::expected Session::run_launch(const Json& p, const rpc::Co const auto root = root_of(p); if (root.empty()) return std::unexpected(invalid("run/launch names its project's root")); std::vector args{"run", "--print-launch"}; - if (p.value("profile", settings_.value("mcpp.build.profile", "dev")) == "release") args.push_back("--release"); - if (auto target = p.value("target", ""); !target.empty()) args.push_back(target); + const auto profile = p.value("profile", setting("mcpp.build.profile").is_string() ? setting("mcpp.build.profile").get() : "dev"); + if (profile == "release") args.push_back("--release"); + for (const auto& a : target_args(p)) args.push_back(a); + if (auto bin = p.value("bin", ""); !bin.empty()) args.push_back(bin); auto r = query(root, std::move(args)); if (!r) return std::unexpected(r.error()); if (ctx.cancelled()) return std::unexpected(rpc::Error{rpc::REQUEST_CANCELLED, "cancelled"}); @@ -385,14 +548,23 @@ std::expected Session::run_launch(const Json& p, const rpc::Co return std::unexpected(rpc::Error{rpc::REQUEST_FAILED, t("the program could not be built"), Json{{"exitCode", r->exitCode}, {"narration", r->narration}, {"diagnostics", mcpp::diagnostics_of(r->envelope)}}}); - return r->envelope["data"]; + Json launch = r->envelope["data"]; + // A program in a terminal: the user's arguments after mcpp's own (a runner's, an image's). + for (const auto& a : strings_of(p.value("args", Json::array()))) launch["argv"].push_back(a); + return launch; } +// A debug session for what `run/launch` describes, in the adapter's debugger's own configuration. +// +// A PROGRAM THAT RUNS THROUGH ANOTHER (`via`: an ok image under `okrun`, a target's runner) is +// debugged as that runner, with the image's symbols arriving through the GDB JIT interface: okrun +// registers each image it loads (`__jit_debug_register_code`), which gdb reads by default and lldb +// reads once its JIT loader is on. Breakpoints in the image's sources then bind when it is loaded. std::expected Session::debug_configuration(const Json& p, const rpc::Context& ctx) { auto launch = run_launch(p, ctx); if (!launch) return launch; const auto& l = *launch; - std::string engine = p.value("engine", settings_.value("mcpp.debug.engine", "auto")); + std::string engine = p.value("engine", setting("mcpp.debug.engine").is_string() ? setting("mcpp.debug.engine").get() : "auto"); const auto available = strings_of(p.value("available", Json::array())); auto has = [&](std::string_view e) { return std::ranges::find(available, e) != available.end(); }; if (engine == "auto") { @@ -405,6 +577,8 @@ std::expected Session::debug_configuration(const Json& p, cons const std::string program = argv.empty() ? l.value("program", "") : argv.front(); std::vector args(argv.size() > 1 ? argv.begin() + 1 : argv.end(), argv.end()); Json env = l.value("env", Json::object()); + const bool through = !l.value("via", Json(nullptr)).is_null(); + const auto jit = std::string("settings set plugin.jit-loader.gdb.enable on"); Json cfg{{"name", std::format("mcpp: {}", std::filesystem::path(l.value("program", program)).filename().string())}, {"request", "launch"}, {"program", program}, {"args", args}, {"cwd", l.value("cwd", root_of(p).generic_string())}}; if (engine == "cppdbg") { @@ -414,23 +588,26 @@ std::expected Session::debug_configuration(const Json& p, cons cfg["environment"] = envList; cfg["MIMode"] = p.value("platform", "linux") == "macos" ? "lldb" : "gdb"; cfg["externalConsole"] = false; + if (through && cfg["MIMode"] == "lldb") cfg["setupCommands"] = Json::array({Json{{"text", jit}}}); } else if (engine == "lldb") { cfg["type"] = "lldb"; cfg["env"] = env; + if (through) cfg["initCommands"] = Json::array({jit}); } else if (engine == "lldb-dap") { cfg["type"] = "lldb-dap"; Json envList = Json::array(); for (auto it = env.begin(); it != env.end(); ++it) envList.push_back(std::format("{}={}", it.key(), it.value().get())); cfg["env"] = envList; + if (through) cfg["initCommands"] = Json::array({jit}); } else if (engine == "gdb") { cfg["type"] = "gdb"; cfg["env"] = env; } else { return std::unexpected(invalid(std::format("unknown debug engine {}", engine))); } - if (!l.value("via", Json(nullptr)).is_null()) - cfg["mcppNote"] = t("this program runs through {0}; the debugger starts it directly", - {l["via"].get()}); + if (through) + cfg["mcppNote"] = t("this program runs through {0}; the debugger starts {0} and reads the program's symbols when it is loaded", + {l["via"].is_string() ? l["via"].get() : program}); return Json{{"engine", engine}, {"configuration", cfg}, {"launch", l}}; } @@ -443,8 +620,7 @@ std::expected Session::library_search(const Json& p) { envelope = searchCache_; } if (envelope.is_null()) { - auto cwd = folders_.empty() ? std::filesystem::current_path() : folders_.front(); - auto r = query(cwd, {"search", "--format", "json"}); + auto r = query(any_root(p), {"search", "--format", "json"}); if (!r) return std::unexpected(r.error()); if (r->envelope.is_null() || r->envelope.value("kind", "") != "mcpp.search") return std::unexpected(rpc::Error{rpc::REQUEST_FAILED, t("mcpp search printed no catalogue"), @@ -467,11 +643,23 @@ std::expected Session::library_search(const Json& p) { return views::library(envelope, q); } -std::expected Session::cache_plan(const Json& p) { +namespace { +policy::CleanOptions clean_options(const Json& p, const Json& settings) { policy::CleanOptions o; - o.staleDays = p.value("staleDays", settings_.value("mcpp.cache.staleDays", 3)); - o.budgetGiB = p.value("budgetGiB", settings_.value("mcpp.cache.gc.defaultBudgetGiB", 0.0)); - o.pruneAgeDays = p.value("pruneAgeDays", settings_.value("mcpp.cache.pruneAgeDays", 30)); + o.staleDays = p.value("staleDays", settings.value("mcpp.cache.staleDays", 3)); + o.budgetGiB = p.value("budgetGiB", settings.value("mcpp.cache.gc.defaultBudgetGiB", 0.0)); + o.pruneAgeDays = p.value("pruneAgeDays", settings.value("mcpp.cache.pruneAgeDays", 30)); + return o; +} +} // namespace + +std::expected Session::cache_plan(const Json& p) { + Json settings; + { + std::lock_guard lock(mutex_); + settings = settings_; + } + const auto o = clean_options(p, settings); auto plan = policy::plan(p.value("action", ""), o); if (!plan) return std::unexpected(invalid(std::format("unknown cache action {}", p.value("action", "")))); Json out = policy::to_json(*plan); @@ -482,12 +670,12 @@ std::expected Session::cache_plan(const Json& p) { out["refusedUntrusted"] = plan->requiresTrust && !trusted_; } if (plan->preview) { - const auto root = root_of(p); + const auto root = any_root(p); if (plan->previewSource == "mcpp") { - auto r = query(root.empty() ? std::filesystem::current_path() : root, plan->previewArgv); + auto r = query(root, plan->previewArgv); if (r) out["preview"] = Json{{"source", "mcpp"}, {"text", r->narration}}; } else { - auto r = query(root.empty() ? std::filesystem::current_path() : root, {"cache", "list", "--format", "json"}); + auto r = query(root, {"cache", "list", "--format", "json"}); if (r) out["preview"] = views::cache_preview(r->envelope, *plan, o); } } @@ -495,11 +683,12 @@ std::expected Session::cache_plan(const Json& p) { } std::expected Session::cache_apply(const Json& p) { - policy::CleanOptions o; - o.staleDays = p.value("staleDays", settings_.value("mcpp.cache.staleDays", 3)); - o.budgetGiB = p.value("budgetGiB", settings_.value("mcpp.cache.gc.defaultBudgetGiB", 0.0)); - o.pruneAgeDays = p.value("pruneAgeDays", settings_.value("mcpp.cache.pruneAgeDays", 30)); - auto plan = policy::plan(p.value("action", ""), o); + Json settings; + { + std::lock_guard lock(mutex_); + settings = settings_; + } + auto plan = policy::plan(p.value("action", ""), clean_options(p, settings)); if (!plan) return std::unexpected(invalid(std::format("unknown cache action {}", p.value("action", "")))); { std::lock_guard lock(mutex_); @@ -508,11 +697,9 @@ std::expected Session::cache_apply(const Json& p) { } if (!policy::confirmed(*plan, p.value("confirmation", Json::object()))) return std::unexpected(rpc::Error{rpc::REQUEST_FAILED, t("this action was not confirmed"), policy::to_json(*plan)}); - auto root = root_of(p); - if (root.empty()) root = folders_.empty() ? std::filesystem::current_path() : folders_.front(); jobs::Request r; r.kind = plan->group == "clean" ? jobs::Kind::clean : jobs::Kind::command; - r.root = root; + r.root = any_root(p); r.args = plan->argv; r.client = client_label(); return Json{{"jobId", jobs_->submit(std::move(r))}}; @@ -533,9 +720,32 @@ std::expected Session::project_summary(const Json& p) { Json summary = views::project_summary(db ? *db : Json(nullptr), projects::last_result(root)); if (!db) summary["error"] = db.error().message; summary["root"] = root.generic_string(); + summary["target"] = setting("mcpp.build.target"); + std::lock_guard lock(mutex_); + if (auto it = plans_.find(root); it != plans_.end()) { + summary["platform"] = (*it).second["platform"]; + summary["platformText"] = (*it).second["platformText"]; + summary["hostPlatform"] = (*it).second["hostPlatform"]; + summary["hostPlatformText"] = (*it).second["hostPlatformText"]; + summary["configuration"] = (*it).second["configuration"]; + } return summary; } +std::expected Session::project_new(const Json& p) { + const auto parent = std::filesystem::path(p.value("parent", "")); + const auto name = p.value("name", ""); + if (parent.empty() || name.empty()) return std::unexpected(invalid("project/new names a parent directory and a name")); + if (name.find_first_of("/\\") != std::string::npos || name == "." || name == "..") + return std::unexpected(invalid(t("a project's name is one directory name: {0}", {name}))); + std::vector args{"new", name}; + if (auto tpl = p.value("template", ""); !tpl.empty()) { args.push_back("--template"); args.push_back(tpl); } + auto started = job_start(Json{{"kind", "command"}, {"root", parent.generic_string()}, {"args", args}, {"color", false}}); + if (!started) return started; + (*started)["root"] = (parent / name).generic_string(); + return started; +} + std::expected Session::manifest_check(const Json& p) { const auto root = root_of(p); if (root.empty()) return std::unexpected(invalid("manifest/check names its project's root")); @@ -557,6 +767,144 @@ std::expected Session::manifest_check(const Json& p) { return Json{{"root", root.generic_string()}, {"diagnostics", diags}}; } +std::expected Session::language_service(const Json& p) { + std::vector candidates = strings_of(p.value("candidates", Json::array())); + { + std::lock_guard lock(mutex_); + if (candidates.empty()) candidates = mcpplsCandidates_; + else mcpplsCandidates_ = candidates; + } + const auto s = languageservice::probe(candidates); + const std::string required(languageservice::kRequired); + Json out{{"state", languageservice::state_name(s.state)}, {"program", s.program.generic_string()}, + {"source", s.source}, {"version", s.version}, {"required", required}}; + Json actions = Json::array(); + switch (s.state) { + case languageservice::State::ok: + out["message"] = t("mcppls {0} at {1}", {s.version, s.program.generic_string()}); + break; + case languageservice::State::outdated: + out["message"] = t("mcppls {0} predates mcpp's result record: a build does not refresh it. Update mcppls to {1} or later.", + {s.version, required}); + actions.push_back(Json{{"id", "update"}, {"title", t("Update mcppls")}}); + break; + case languageservice::State::missing: + out["message"] = t("mcppls was not found: C++ files have no completion, navigation or diagnostics from mcpp's build. Install the C++ Modules language server ({0} or later).", + {required}); + actions.push_back(Json{{"id", "install"}, {"title", t("Install mcppls")}}); + break; + case languageservice::State::unreadable: + out["message"] = t("mcppls at {0} did not report its version: {1}", {s.program.generic_string(), s.detail}); + actions.push_back(Json{{"id", "update"}, {"title", t("Update mcppls")}}); + break; + } + out["actions"] = actions; + return out; +} + +std::expected Session::targets(const Json& p) { + auto r = query(any_root(p), {"toolchain", "list", "--format", "json"}); + if (!r) return std::unexpected(r.error()); + const auto chosen = p.contains("selected") && p["selected"].is_string() ? p["selected"].get() + : setting("mcpp.build.target").is_string() ? setting("mcpp.build.target").get() : std::string{}; + Json out = views::targets(r->envelope, chosen); + if (const auto root = root_of(p); !root.empty()) { + std::lock_guard lock(mutex_); + if (auto it = plans_.find(root); it != plans_.end()) out["lastPlan"] = it->second; + } + return out; +} + +// The command table for one editor, in the user's language: what the adapter registers at run time +// beside the declarations generated from the same table (spec/commands.json). +std::expected Session::commands(const Json& p) const { + std::string editor, locale; + { + std::lock_guard lock(mutex_); + editor = p.value("editor", editor_); + } + { + std::lock_guard lock(localeMutex_); + locale = locale_; + } + const auto& table = spec::commands(); + Json groups = Json::object(); + for (const auto& g : table["groups"]) groups[g.value("id", "")] = spec::manifest_string(g.value("title", ""), locale); + Json out = Json::array(); + for (const auto& c : table["commands"]) { + if (!offered_in(c, editor)) continue; + Json row = c; + const auto id = c.value("id", ""); + row["title"] = spec::manifest_string(std::format("command.{}.title", id), locale); + row["groupTitle"] = groups.value(c.value("group", ""), ""); + out.push_back(std::move(row)); + } + return Json{{"editor", editor}, {"commands", out}}; +} + +// The quick menu: the commands marked for it, each with whether it can run now and why not. +std::expected Session::quick_menu(const Json& p) { + auto table = commands(p); + if (!table) return table; + const auto root = root_of(p); + bool ready, trusted; + { + std::lock_guard lock(mutex_); + ready = client_.ready(); + trusted = trusted_; + } + const bool running = [&] { + for (const auto& j : jobs_->list()) if (j.value("root", "") == root.lexically_normal().generic_string()) return true; + return false; + }(); + Json items = Json::array(); + for (const auto& c : (*table)["commands"]) { + if (!c.value("quickMenu", false)) continue; + const auto when = c.value("when", ""); + std::string disabled; + if (when.find("mcpp.inProject") != std::string::npos && root.empty()) disabled = t("No mcpp project in this workspace"); + else if (!ready && c["action"].value("kind", "") != "panel" && c["action"].value("kind", "") != "selfCheck") + disabled = t("mcpp is not available"); + Json item{{"command", c["id"]}, {"title", c["title"]}, {"group", c["groupTitle"]}, {"enabled", disabled.empty()}}; + if (!disabled.empty()) item["reason"] = disabled; + if (c["action"].value("kind", "") == "job" && running) item["detail"] = t("runs after the job in progress"); + if (!trusted && c["action"].value("kind", "") == "job") item["detail"] = t("the workspace is not trusted: mcpp runs with effects denied"); + items.push_back(std::move(item)); + } + return Json{{"items", items}}; +} + +// The tests of a project, without building them: `mcpp test --list --message-format json` (one +// record per test, with the file that holds its `main`), else the test targets of the build database. +std::expected Session::test_list(const Json& p) { + const auto root = root_of(p); + if (root.empty()) return std::unexpected(invalid("test/list names its project's root")); + mcpp::Client client; + { + std::lock_guard lock(mutex_); + client = client_; + } + Json tests = Json::array(); + if (client.ready()) { + mcpp::RunOptions o; + o.cwd = root; + o.args = {"test", "--list", "--message-format", "json"}; + for (const auto& a : target_args(p)) o.args.push_back(a); + o.deny = deny(); + o.client = client_label(); + if (auto r = client.records(o); r && r->exitCode == 0) + for (const auto& rec : r->records) + if (rec.is_object() && rec.contains("test") && rec["test"].is_string()) + tests.push_back(Json{{"test", rec["test"]}, {"member", rec.value("member", "")}, {"main", rec.value("main", "")}}); + } + if (tests.empty()) { + auto db = build_database(root); + if (db) for (const auto& row : views::project_summary(*db, Json(nullptr))["tests"]) + tests.push_back(Json{{"test", row.value("name", "")}, {"member", ""}, {"main", ""}}); + } + return Json{{"root", root.generic_string()}, {"tests", tests}}; +} + void Session::install() { auto& s = rpc_; s.on("initialize", [this](const Json& p, const rpc::Context&) { return initialize(p); }); @@ -568,12 +916,24 @@ void Session::install() { return *preset; }); s.on("i18n/bundle", [this](const Json& p, const rpc::Context&) -> Result { - return i18n::bundle(p.value("locale", locale_)); + std::string locale; + { + std::lock_guard lock(localeMutex_); + locale = locale_; + } + return i18n::bundle(p.value("locale", locale)); }); s.on("selfCheck", [this](const Json&, const rpc::Context&) -> Result { locate_mcpp(); return self_check(); }); + s.on("commands/list", [this](const Json& p, const rpc::Context&) { return commands(p); }); + s.on("menu/quick", [this](const Json& p, const rpc::Context&) { return quick_menu(p); }); + s.on("languageService/status", [this](const Json& p, const rpc::Context&) { return language_service(p); }); s.on("projects/list", [this](const Json& p, const rpc::Context&) -> Result { Json out = Json::array(); - std::vector folders = folders_; + std::vector folders; + { + std::lock_guard lock(mutex_); + folders = folders_; + } for (const auto& f : strings_of(p.value("folders", Json::array()))) folders.emplace_back(f); for (const auto& folder : folders) for (const auto& proj : projects::discover(folder, p.value("depth", 4))) { @@ -589,6 +949,7 @@ void Session::install() { return project_json(*proj); }); s.on("project/summary", [this](const Json& p, const rpc::Context&) { return project_summary(p); }); + s.on("project/new", [this](const Json& p, const rpc::Context&) { return project_new(p); }); s.on("result/last", [](const Json& p, const rpc::Context&) -> Result { return projects::last_result(root_of(p)); }); s.on("job/start", [this](const Json& p, const rpc::Context&) { return job_start(p); }); s.on("job/cancel", [this](const Json& p, const rpc::Context&) -> Result { @@ -597,9 +958,10 @@ void Session::install() { s.on("job/list", [this](const Json&, const rpc::Context&) -> Result { return jobs_->list(); }); s.on("run/launch", [this](const Json& p, const rpc::Context& c) { return run_launch(p, c); }); s.on("debug/configuration", [this](const Json& p, const rpc::Context& c) { return debug_configuration(p, c); }); + s.on("test/list", [this](const Json& p, const rpc::Context&) { return test_list(p); }); s.on("library/search", [this](const Json& p, const rpc::Context&) { return library_search(p); }); s.on("library/indexes", [this](const Json& p, const rpc::Context&) -> Result { - auto r = query(root_of(p).empty() ? std::filesystem::current_path() : root_of(p), {"index", "list", "--format", "json"}); + auto r = query(any_root(p), {"index", "list", "--format", "json"}); if (!r) return std::unexpected(r.error()); return r->envelope.is_object() ? r->envelope["data"] : Json(nullptr); }); @@ -614,31 +976,33 @@ void Session::install() { std::lock_guard lock(mutex_); searchCache_ = nullptr; } - auto root = root_of(p).empty() ? (folders_.empty() ? std::filesystem::current_path() : folders_.front()) : root_of(p); - return job_start(Json{{"kind", "command"}, {"root", root.generic_string()}, {"args", Json::array({"index", "update"})}}); + return job_start(Json{{"kind", "command"}, {"root", any_root(p).generic_string()}, {"args", Json::array({"index", "update"})}}); }); s.on("toolchains/list", [this](const Json& p, const rpc::Context&) -> Result { - auto r = query(root_of(p).empty() ? std::filesystem::current_path() : root_of(p), {"toolchain", "list", "--format", "json"}); + auto r = query(any_root(p), {"toolchain", "list", "--format", "json"}); if (!r) return std::unexpected(r.error()); return views::toolchains(r->envelope); }); s.on("toolchains/install", [this](const Json& p, const rpc::Context&) -> Result { - auto root = root_of(p).empty() ? (folders_.empty() ? std::filesystem::current_path() : folders_.front()) : root_of(p); - return job_start(Json{{"kind", "toolchain"}, {"root", root.generic_string()}, {"spec", p.value("spec", "")}}); + Json job{{"kind", "toolchain"}, {"root", any_root(p).generic_string()}, {"spec", p.value("spec", "")}}; + if (p.contains("target")) job["target"] = p["target"]; + return job_start(job); }); s.on("toolchains/setDefault", [this](const Json& p, const rpc::Context&) -> Result { auto spec = p.value("spec", ""); if (spec.empty()) return std::unexpected(invalid("toolchains/setDefault names a spec")); - auto r = query(root_of(p).empty() ? std::filesystem::current_path() : root_of(p), {"toolchain", "default", spec}); + auto r = query(any_root(p), {"toolchain", "default", spec}); if (!r) return std::unexpected(r.error()); if (r->exitCode != 0) return std::unexpected(rpc::Error{rpc::REQUEST_FAILED, r->narration}); return Json{{"spec", spec}}; }); + s.on("targets/list", [this](const Json& p, const rpc::Context&) { return targets(p); }); s.on("cache/inventory", [this](const Json& p, const rpc::Context&) -> Result { - auto r = query(std::filesystem::current_path(), {"cache", "list", "--format", "json"}); + auto r = query(any_root(p), {"cache", "list", "--format", "json"}); if (!r) return std::unexpected(r.error()); views::CacheOptions o; - o.topN = p.value("topN", settings_.value("mcpp.views.cache.topN", 5)); + const auto topN = setting("mcpp.views.cache.topN"); + o.topN = p.value("topN", topN.is_number() ? topN.get() : 5); return views::cache_inventory(r->envelope, o); }); s.on("cache/plan", [this](const Json& p, const rpc::Context&) { return cache_plan(p); }); @@ -646,10 +1010,15 @@ void Session::install() { s.on("graph/packages", [this](const Json& p, const rpc::Context&) { return graph(p, false); }); s.on("graph/modules", [this](const Json& p, const rpc::Context&) { return graph(p, true); }); s.on("pack/formats", [this](const Json& p, const rpc::Context&) -> Result { - auto r = query(root_of(p), {"pack", "--list-formats"}); + auto r = query(any_root(p), {"pack", "--list-formats"}); if (!r) return std::unexpected(r.error()); return r->envelope.is_object() ? r->envelope["data"] : Json(nullptr); }); + s.on("pack/start", [this](const Json& p, const rpc::Context&) -> Result { + Json job = p; + job["kind"] = "pack"; + return job_start(job); + }); s.on("manifest/check", [this](const Json& p, const rpc::Context&) { return manifest_check(p); }); s.on("toml/complete", [](const Json& p, const rpc::Context&) -> Result { return manifest::complete(p); }); s.on("toml/hover", [](const Json& p, const rpc::Context&) -> Result { return manifest::hover(p); }); diff --git a/src/spec.cppm b/src/spec.cppm index 03b25c0..c2f53e5 100644 --- a/src/spec.cppm +++ b/src/spec.cppm @@ -28,6 +28,13 @@ const Json& presets(); // spec/presets.json's "presets" const std::map>& runtime_zh_cn(); const Json& toml_schema(); const Json& buildscript_api(); +// spec/commands.json: the command table both adapters declare (groups, commands). +const Json& commands(); +// The editors' strings (command titles, setting titles, view names): spec/i18n/manifest..json. +// "zh-cn" falls back to English key by key. +const Json& manifest_strings(std::string_view locale); +// One editor string; the key itself when no bundle has it. +std::string manifest_string(std::string_view key, std::string_view locale); } // namespace mcppide::spec @@ -87,4 +94,26 @@ const Json& buildscript_api() { return a; } +const Json& commands() { + static const Json c = Json::parse(generated::kCommandsJson); + return c; +} + +const Json& manifest_strings(std::string_view locale) { + static const Json en = Json::parse(generated::kManifestEnJson); + static const Json zh = [] { + Json z = en; + const auto zhStrings = Json::parse(generated::kManifestZhCnJson); + for (auto it = zhStrings.begin(); it != zhStrings.end(); ++it) z[it.key()] = it.value(); + return z; + }(); + return locale == "zh-cn" ? zh : en; +} + +std::string manifest_string(std::string_view key, std::string_view locale) { + const auto& m = manifest_strings(locale); + if (auto it = m.find(std::string(key)); it != m.end() && it->is_string()) return it->get(); + return std::string(key); +} + } // namespace mcppide::spec diff --git a/src/views.cppm b/src/views.cppm index 07c6184..e45d534 100644 --- a/src/views.cppm +++ b/src/views.cppm @@ -9,6 +9,9 @@ // package_graph `mcpp emit build-database` sets and what each sees // module_graph the same modules, who provides, who imports // project_summary the same and the result record targets, tests, artifacts, last build +// targets `mcpp toolchain list --format json` one row per target: its toolchains, its platform +// platform_text a `platform` object of mcpp's "openkal-platform 0.17.1 (built-in)" +// stream_record one record of a `--message-format json` stream, normalised export module mcppide.views; import std; @@ -43,6 +46,18 @@ Json package_graph(const Json& buildDatabaseEnvelope); Json module_graph(const Json& buildDatabaseEnvelope); Json project_summary(const Json& buildDatabaseEnvelope, const Json& lastResult); +// The targets mcpp knows, one row each, with the toolchains installed for it and, where mcpp +// reports one (design 2026-10-28 §9), the platform that configures it. `selected` is the target the +// adapter builds for ("" for the host). +Json targets(const Json& toolchainListEnvelope, std::string_view selected); +// "openkal-platform 0.17.1 (built-in)", "host conventions (built-in)"; "" for null or a non-object. +std::string platform_text(const Json& platform); + +// One record of a `--message-format json` stream (a build's events, a test's records), as the +// adapters consume it: {"type": "plan" | "progress" | "diagnostic" | "artifact" | "test" | "summary" | +// "other", ...}. +Json stream_record(const Json& record); + // "1.5 GiB" -- binary units, one decimal. std::string format_bytes(std::int64_t bytes); @@ -351,4 +366,105 @@ Json project_summary(const Json& envelope, const Json& lastResult) { return out; } +std::string platform_text(const Json& p) { + if (!p.is_object()) return {}; + const auto name = p.value("name", ""); + const auto version = p.contains("version") && p["version"].is_string() ? p["version"].get() : std::string{}; + const auto source = p.value("source", ""); + std::string out = name.empty() ? std::string("host conventions") : name; + if (!version.empty()) out += " " + version; + if (!source.empty()) out += " (" + source + ")"; + return out; +} + +Json targets(const Json& envelope, std::string_view selected) { + const auto& data = data_of(envelope); + const auto host = data.value("host", ""); + std::map rows; + std::vector order; + if (data.contains("targets") && data["targets"].is_array()) + for (const auto& t : data["targets"]) { + if (!t.is_object()) continue; + const auto target = t.value("target", ""); + if (target.empty()) continue; + auto [it, fresh] = rows.try_emplace(target, Json{{"target", target}, {"note", t.value("note", "")}, + {"pin", t.value("pin", "")}, {"tier", t.value("tier", "")}, + {"host", target == host}, {"toolchains", Json::array()}, + {"platform", nullptr}}); + if (fresh) order.push_back(target); + auto& row = it->second; + // mcpp reports the platform per row of the target table; every row of one target names the same. + if (row["platform"].is_null() && t.contains("platform") && t["platform"].is_object()) row["platform"] = t["platform"]; + auto tc = t.value("toolchain", ""); + const auto sp = tc.find(' '); + if (sp != std::string::npos) tc[sp] = '@'; + if (sp != std::string::npos || !t.value("status", "").empty()) + row["toolchains"].push_back(Json{{"spec", sp == std::string::npos ? std::string{} : tc}, + {"status", t.value("status", "")}, {"default", t.value("default", false)}}); + } + Json out = Json::array(); + const std::string chosen = selected.empty() ? host : std::string(selected); + for (const auto& name : order) { + auto row = rows[name]; + row["platformText"] = platform_text(row["platform"]); + row["selected"] = name == chosen; + bool installed = false; + for (const auto& tc : row["toolchains"]) installed = installed || tc.value("status", "") == "installed"; + row["installed"] = installed; + out.push_back(std::move(row)); + } + Json result{{"host", host}, {"selected", chosen}, {"rows", out}, {"hostPlatform", nullptr}}; + if (data.contains("hostPlatform") && data["hostPlatform"].is_object()) { + result["hostPlatform"] = data["hostPlatform"]; + result["hostPlatformText"] = platform_text(data["hostPlatform"]); + } + return result; +} + +Json stream_record(const Json& r) { + if (!r.is_object()) return Json{{"type", "other"}, {"record", r}}; + // `mcpp test --message-format json`: one record per test, then the summary. + if (r.contains("summary") && r["summary"].is_object()) { + const auto& s = r["summary"]; + return Json{{"type", "summary"}, {"member", s.value("member", "")}, {"passed", s.value("passed", 0)}, + {"failed", s.value("failed", 0)}, {"notRun", s.value("not_run", 0)}, + {"notRunReason", s.value("not_run_reason", "")}, {"elapsedMs", s.value("elapsed_ms", 0)}}; + } + if (r.contains("test") && r["test"].is_string()) { + const auto raw = r.value("status", ""); + const std::string status = raw == "pass" ? "passed" + : raw == "fail" ? (r.value("timed_out", false) ? "timedOut" : "failed") + : raw == "skip" || raw == "not_run" ? "skipped" : "errored"; + std::string output = r.value("compile_output", ""); + output += r.value("run_output", ""); + return Json{{"type", "test"}, {"member", r.value("member", "")}, {"test", r["test"]}, {"status", status}, + {"durationMs", r.value("duration_ms", 0)}, {"exitCode", r.contains("exit_code") ? r["exit_code"] : Json(nullptr)}, + {"reason", r.value("reason", "")}, {"output", output}}; + } + const auto event = r.value("event", ""); + if (r.value("kind", "") == "mcpp.event") { + if (event == "plan") { + Json out{{"type", "plan"}, {"configuration", r.contains("configuration") ? r["configuration"] : Json(nullptr)}, + {"platform", r.contains("platform") ? r["platform"] : Json(nullptr)}, + {"hostPlatform", r.contains("hostPlatform") ? r["hostPlatform"] : Json(nullptr)}}; + out["platformText"] = platform_text(out["platform"]); + out["hostPlatformText"] = platform_text(out["hostPlatform"]); + return out; + } + if (event == "progress") + return Json{{"type", "progress"}, {"finished", r.value("finished", 0)}, {"total", r.value("total", 0)}}; + if (event == "artifact" && r.contains("artifact") && r["artifact"].is_object()) + return Json{{"type", "artifact"}, {"artifact", r["artifact"]}}; + if (event == "diagnostic" && r.contains("diagnostic") && r["diagnostic"].is_object()) { + const auto& d = r["diagnostic"]; + Json n{{"type", "diagnostic"}, {"severity", d.value("severity", "error")}, {"message", d.value("message", "")}, + {"code", d.value("code", "")}, {"source", "mcpp"}}; + if (d.contains("path") && d["path"].is_string()) n["path"] = d["path"]; + if (d.contains("range") && d["range"].is_object()) n["range"] = d["range"]; + return n; + } + } + return Json{{"type", "other"}, {"record", r}}; +} + } // namespace mcppide::views diff --git a/tests/test_languageservice.cpp b/tests/test_languageservice.cpp new file mode 100644 index 0000000..e1d6866 --- /dev/null +++ b/tests/test_languageservice.cpp @@ -0,0 +1,25 @@ +// The mcppls handshake: the version is read from either spelling of `--version`, 0.0.18 and later +// read the result record, an older one is `outdated`, and output with no version is `unreadable`. +#include "support.hpp" +import std; +import mcppide.languageservice; + +using namespace mcppide; +namespace ls = mcppide::languageservice; + +int main() { + CHECK(ls::version_in("0.0.16\n") == "0.0.16"); + CHECK(ls::version_in("mcppls 0.0.18\n") == "0.0.18"); + CHECK(ls::version_in("mcppls 0.0.19,\n") == "0.0.19"); + CHECK(ls::version_in("mcppls\n").empty()); + CHECK(ls::classify("/x/mcppls", "PATH", "0.0.16\n").state == ls::State::outdated); + CHECK(ls::classify("/x/mcppls", "PATH", "mcppls 0.0.18\n").state == ls::State::ok); + CHECK(ls::classify("/x/mcppls", "PATH", "0.1.0").state == ls::State::ok); + CHECK(ls::classify("/x/mcppls", "PATH", "usage: mcppls").state == ls::State::unreadable); + // A candidate that does not exist is passed over; with nothing found the state is `missing` or + // whatever the machine's own mcppls answers -- never an error. + const auto s = ls::probe({"/no/such/mcppls"}); + CHECK(s.program != std::filesystem::path("/no/such/mcppls")); + CHECK(ls::state_name(ls::State::outdated) == "outdated"); + std::println("test_languageservice: ok"); +} diff --git a/tests/test_protocol.cpp b/tests/test_protocol.cpp new file mode 100644 index 0000000..87eb988 --- /dev/null +++ b/tests/test_protocol.cpp @@ -0,0 +1,160 @@ +// The two contracts, held to their schemas: +// - every golden fixture (mcpp's real output) against the definition of +// protocol/mcpp-contract.schema.json that protocol/fixtures.json names for it; +// - the methods the backend registers and the notifications it sends against +// protocol/protocol.schema.json, both ways; +// - a session over the mock mcpp: each answer against its method's `result`, and +// every notification a build and a test send against its `params`. +#include "support.hpp" +import std; +import nlohmann.json; +import mcppide.rpc; +import mcppide.server; +import mcppide.schema; + +using namespace mcppide; +using Json = nlohmann::json; + +namespace { + +Json load(const std::filesystem::path& p) { return Json::parse(testsupport::read(p)); } + +bool conforms(const Json& value, const Json& schema, const Json& root, std::string_view what) { + const auto problems = schema::validate(value, schema, root); + for (const auto& p : problems) std::println(std::cerr, "{}: {}", what, p); + return problems.empty(); +} + +// A session on an in-process wire: requests are dispatched, answers and notifications collected. +struct Wire { + std::mutex lock; + std::vector messages; + rpc::Server server{[this](std::string_view frame) { + rpc::FrameReader r; + r.feed(frame); + std::lock_guard g(lock); + while (auto body = r.next()) messages.push_back(Json::parse(*body)); + return true; + }}; + int next = 1; + + Json call(std::string_view method, Json params) { + const int id = next++; + server.dispatch(Json{{"jsonrpc", "2.0"}, {"id", id}, {"method", method}, {"params", std::move(params)}}.dump()); + for (int i = 0; i < 3000; ++i) { + { + std::lock_guard g(lock); + for (const auto& m : messages) if (m.contains("id") && m["id"] == id) return m; + } + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + } + return Json{{"error", {{"message", "no answer"}}}}; + } + std::vector notifications(std::string_view method) { + std::lock_guard g(lock); + std::vector out; + for (const auto& m : messages) if (m.value("method", "") == method) out.push_back(m["params"]); + return out; + } +}; + +} // namespace + +int main() { + const auto contract = load(testsupport::repo() / "protocol" / "mcpp-contract.schema.json"); + const auto index = load(testsupport::repo() / "protocol" / "fixtures.json"); + for (const auto& f : index["fixtures"]) { + const auto path = testsupport::fixtures() / f["file"].get(); + if (!std::filesystem::exists(path)) { + CHECK(f.value("optional", false)); + continue; + } + const auto text = testsupport::read(path); + if (f.contains("each")) { + const Json def{{"$ref", "#/$defs/" + f["each"].get()}}; + std::istringstream lines(text); + int n = 0; + for (std::string line; std::getline(lines, line);) { + if (line.empty()) continue; + CHECK(conforms(Json::parse(line), def, contract, std::format("{}:{}", f["file"].get(), ++n))); + } + CHECK(n > 0); + } else { + const Json def{{"$ref", "#/$defs/" + f["schema"].get()}}; + CHECK(conforms(Json::parse(text), def, contract, f["file"].get())); + } + } + + const auto protocol = load(testsupport::repo() / "protocol" / "protocol.schema.json"); + std::set methods, notifications; + for (auto it = protocol["methods"].begin(); it != protocol["methods"].end(); ++it) methods.insert(it.key()); + for (auto it = protocol["notifications"].begin(); it != protocol["notifications"].end(); ++it) notifications.insert(it.key()); + std::set registered(server::kMethods.begin(), server::kMethods.end()); + std::set sent(server::kNotifications.begin(), server::kNotifications.end()); + for (const auto& m : methods) if (!registered.contains(m)) std::println(std::cerr, "schema method not registered: {}", m); + for (const auto& m : registered) if (!methods.contains(m)) std::println(std::cerr, "registered method not in the schema: {}", m); + CHECK(methods == registered); + CHECK(notifications == sent); + + // A session over the mock mcpp. + const auto mock = testsupport::built("mcpp-ide-mock-mcpp"); + CHECK(!mock.empty()); + const auto root = std::filesystem::temp_directory_path() / std::format("mcppide-protocol-{}", std::chrono::steady_clock::now().time_since_epoch().count()); + std::filesystem::create_directories(root / "src"); + std::ofstream(root / "mcpp.toml") << "[package]\nname = \"app\"\nversion = \"0.1.0\"\n"; + Wire wire; + server::Session session(wire.server); + session.install(); + auto result_of = [&](std::string_view method, Json params) { + auto answer = wire.call(method, std::move(params)); + if (!answer.contains("result")) std::println(std::cerr, "{}: {}", method, answer.dump()); + CHECK(answer.contains("result")); + const auto& def = protocol["methods"][std::string(method)]["result"]; + CHECK(conforms(answer["result"], def, protocol, method)); + return answer["result"]; + }; + auto init = result_of("initialize", Json{{"client", {{"name", "test"}}}, {"editor", "vscode"}, + {"settings", {{"mcpp.path", mock.generic_string()}}}, + {"workspaceFolders", Json::array({root.generic_string()})}}); + CHECK(init["projects"].size() == 1); + CHECK(init["mcpp"].is_object() && init["mcpp"]["contract"] == true); + const Json rooted{{"root", root.generic_string()}}; + result_of("project/summary", rooted); + auto tests = result_of("test/list", rooted); + CHECK(tests["tests"].size() == 1 && tests["tests"][0]["test"] == "test_smoke"); + auto targets = result_of("targets/list", rooted); + CHECK(!targets["rows"].empty()); + auto cmds = result_of("commands/list", Json{{"editor", "jetbrains"}}); + for (const auto& c : cmds["commands"]) CHECK(c["action"]["kind"] != "forward"); + result_of("menu/quick", rooted); + result_of("languageService/status", Json{{"candidates", Json::array()}}); + result_of("graph/packages", rooted); + result_of("graph/modules", rooted); + result_of("manifest/check", rooted); + result_of("settings/registry", Json::object()); + result_of("selfCheck", Json::object()); + result_of("cache/inventory", Json::object()); + auto launch = result_of("run/launch", rooted); + CHECK(!launch["argv"].empty()); + result_of("debug/configuration", Json{{"root", root.generic_string()}, {"available", Json::array({"lldb"})}}); + + result_of("job/start", Json{{"kind", "build"}, {"root", root.generic_string()}}); + result_of("job/start", Json{{"kind", "test"}, {"root", root.generic_string()}}); + for (int i = 0; i < 2000 && wire.notifications("job/finished").size() < 2; ++i) + std::this_thread::sleep_for(std::chrono::milliseconds(5)); + CHECK(wire.notifications("job/finished").size() == 2); + for (const auto& name : server::kNotifications) { + const auto& def = protocol["notifications"][std::string(name)]["params"]; + for (const auto& n : wire.notifications(name)) CHECK(conforms(n, def, protocol, name)); + } + CHECK(!wire.notifications("job/plan").empty()); + CHECK(!wire.notifications("job/artifact").empty()); + const auto results = wire.notifications("test/result"); + CHECK(results.size() == 1 && results[0]["status"] == "passed"); + CHECK(wire.notifications("test/summary").size() == 1); + // The plan a build sent is the project's configuration from then on. + auto after = result_of("project/summary", rooted); + CHECK(after.contains("configuration")); + std::filesystem::remove_all(root); + std::println("test_protocol: ok"); +} diff --git a/tests/test_views.cpp b/tests/test_views.cpp index 049c90d..e25d511 100644 --- a/tests/test_views.cpp +++ b/tests/test_views.cpp @@ -58,5 +58,48 @@ int main() { CHECK(summary["targets"].size() == 1 && summary["tests"].size() == 1); CHECK(summary["lastBuild"]["status"] == "ok" && !summary["artifacts"].empty()); CHECK(views::format_bytes(1536) == "1.5 KiB"); + + // Targets: one row per target, the selected one marked, and the platform a row names (the shape + // of mcpp's platform object, design 2026-10-28 §9) carried and rendered. + auto list = fixture("toolchain-list.json"); + auto t = views::targets(list, ""); + CHECK(!t["rows"].empty()); + std::set seen; + int selected = 0; + for (const auto& r : t["rows"]) { + CHECK(seen.insert(r["target"].get()).second); + if (r["selected"].get()) { ++selected; CHECK(r["target"] == t["host"]); } + CHECK(r["platform"].is_null() == r["platformText"].get().empty()); + } + CHECK(selected == 1); + Json platform{{"name", "openkal-platform"}, {"version", "0.17.1"}, {"source", "built-in"}}; + platform["fields"]["runner"] = Json{{"value", "okrun"}, {"source", "platform"}}; + list["data"]["targets"].push_back(Json{{"target", "x86_64-openkal"}, {"toolchain", "llvm 23.1.3"}, {"pin", "llvm@23.1.3"}, + {"status", "installed"}, {"default", false}, {"note", "ok"}, {"platform", platform}}); + list["data"]["hostPlatform"] = Json{{"name", ""}, {"version", nullptr}, {"source", "built-in"}}; + auto withPlatform = views::targets(list, "x86_64-openkal"); + bool found = false; + for (const auto& r : withPlatform["rows"]) + if (r["target"] == "x86_64-openkal") { + found = true; + CHECK(r["selected"] == true); + CHECK(r["platformText"] == "openkal-platform 0.17.1 (built-in)"); + } + CHECK(found); + CHECK(withPlatform["hostPlatformText"] == "host conventions (built-in)"); + + // Stream records: each line of a build and of a test, normalised. + std::istringstream build(testsupport::read(testsupport::fixtures() / "build-failed.ndjson")); + std::set types; + for (std::string line; std::getline(build, line);) + if (!line.empty()) types.insert(views::stream_record(Json::parse(line))["type"].get()); + CHECK(types.contains("plan") && types.contains("progress") && types.contains("diagnostic")); + std::istringstream test(testsupport::read(testsupport::fixtures() / "test.ndjson")); + std::string first; + std::getline(test, first); + auto r = views::stream_record(Json::parse(first)); + CHECK(r["type"] == "test" && r["status"] == "passed" && r["test"] == "test_smoke"); + auto failed = views::stream_record(Json{{"test", "t"}, {"status", "fail"}, {"timed_out", true}}); + CHECK(failed["status"] == "timedOut"); std::println("test_views: ok"); } diff --git a/tools/capture-fixtures.sh b/tools/capture-fixtures.sh deleted file mode 100755 index 810d955..0000000 --- a/tools/capture-fixtures.sh +++ /dev/null @@ -1,58 +0,0 @@ -#!/usr/bin/env bash -# Captures the golden fixtures under protocol/fixtures from a real mcpp: the -# envelopes, streams and records the backend reads. Both adapters' tests and -# the backend's mock mcpp (src/bin/mockmcpp.cpp) replay them, so a change in -# mcpp's contract shows up as a diff here first. -# -# Usage: MCPP=/path/to/mcpp tools/capture-fixtures.sh -set -euo pipefail -MCPP="${MCPP:-mcpp}" -ROOT="$(cd "$(dirname "$0")/.." && pwd)" -OUT="$ROOT/protocol/fixtures" -TMP=$(mktemp -d) -trap 'rm -rf "$TMP"' EXIT -mkdir -p "$OUT" -export NO_COLOR=1 MCPP_CLIENT=mcpp-ide-fixtures - -# Paths in the fixtures are the temporary project's; the replay rewrites -# @ROOT@ to the directory a test runs in. -scrub() { sed -e "s#$TMP/app#@ROOT@#g" -e "s#$HOME#@HOME@#g"; } - -"$MCPP" --version | head -1 > "$OUT/version.txt" -"$MCPP" --protocol-version > "$OUT/protocol-version.json" - -cd "$TMP" -"$MCPP" new app > /dev/null -cd app -"$MCPP" build --message-format json 2> /dev/null | scrub > "$OUT/build-ok.ndjson" -python3 - "$TMP/app/target/.last-result.json" > "$OUT/result-ok.json" <<'PY' -import json, sys -last = json.load(open(sys.argv[1])) -print(json.dumps(json.load(open(last["data"]["result"])), indent=2)) -PY -sed -i "s#$TMP/app#@ROOT@#g; s#$HOME#@HOME@#g" "$OUT/result-ok.json" -"$MCPP" run --print-launch 2> /dev/null | scrub > "$OUT/launch.json" -"$MCPP" test --message-format json 2> /dev/null | scrub > "$OUT/test.ndjson" || true -"$MCPP" emit build-database --format json 2> /dev/null | scrub > "$OUT/build-database.json" -"$MCPP" search --format json 2> /dev/null | head -c 2000000 | scrub > "$OUT/search.json" || true -"$MCPP" index list --format json 2> /dev/null | scrub > "$OUT/index-list.json" -"$MCPP" pack --list-formats 2> /dev/null | scrub > "$OUT/pack-formats.json" -"$MCPP" toolchain list --format json 2> /dev/null | scrub > "$OUT/toolchain-list.json" -"$MCPP" cache list --format json 2> /dev/null | scrub > "$OUT/cache-list.json" -"$MCPP" self env --format json 2> /dev/null | scrub > "$OUT/self-env.json" -printf 'int main() { return undeclared_name; }\n' > src/main.cpp -"$MCPP" build --message-format json 2> /dev/null | scrub > "$OUT/build-failed.ndjson" || true -printf '[package\nname = "app"\n' > mcpp.toml -"$MCPP" build --message-format json 2> /dev/null | scrub > "$OUT/build-manifest-error.ndjson" || true -# A developer's home holds hundreds of cache entries and the index hundreds of -# packages; the fixtures keep enough of each to exercise every field. -python3 - "$OUT" <<'PY' -import json, sys, os -out = sys.argv[1] -for name, key, n in (("cache-list.json", "entries", 40), ("search.json", "packages", 60)): - p = os.path.join(out, name) - d = json.load(open(p)) - d["data"][key] = d["data"][key][:n] - json.dump(d, open(p, "w"), indent=2) -PY -echo "fixtures from $(cat "$OUT/version.txt") in $OUT" From 9caee86071550b61b3668abfa5f1fa3b17d1862c Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Wed, 28 Oct 2026 02:42:22 +0900 Subject: [PATCH 02/30] backend: settings registry in the session's language with its groups and presets; the mock mcpp reads its failure from the project; LICENSE The mock mcpp also takes `.mock-mcpp-fail` in the project directory, so an editor's test can make a build fail through a backend it did not start. Deprecated settings carry their deprecation message in both languages. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .gitignore | 2 + LICENSE | 201 ++++++++++++++++++++++++++++++++++ spec/i18n/manifest.en.json | 25 ++++- spec/i18n/manifest.zh-cn.json | 25 ++++- src/bin/mockmcpp.cpp | 17 ++- src/server.cppm | 5 +- src/settings.cppm | 23 +++- src/spec.cppm | 7 ++ 8 files changed, 294 insertions(+), 11 deletions(-) create mode 100644 LICENSE diff --git a/.gitignore b/.gitignore index bb36b3d..baffece 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ jetbrains/.intellijPlatform/ webui/dist/ *.log compile_commands.json +dist-upload/ +jetbrains/.kotlin/ diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/spec/i18n/manifest.en.json b/spec/i18n/manifest.en.json index 25e9348..597c5dd 100644 --- a/spec/i18n/manifest.en.json +++ b/spec/i18n/manifest.en.json @@ -240,5 +240,28 @@ "mcpp.trust.denyEffects.title": "Effects denied in an untrusted workspace", "mcpp.trust.denyEffects.description": "What mcpp may not do while the workspace is not trusted (mcpp --deny): a run that needs one of them stops before it and says so. Trusting the workspace lifts the list.", "mcpp.debug.engine.title": "Choose the debugger", - "mcpp.debug.engine.description": "The debug adapter a debug session uses. auto: CodeLLDB when it is installed, then the C/C++ extension's gdb or lldb, then lldb-dap." + "mcpp.debug.engine.description": "The debug adapter a debug session uses. auto: CodeLLDB when it is installed, then the C/C++ extension's gdb or lldb, then lldb-dap.", + "settings.group.project": "Project", + "settings.group.tasks": "Tasks", + "settings.group.languageService": "C++ Modules language service", + "settings.group.toml": "mcpp.toml editing", + "settings.group.buildScript": "build.mcpp editing", + "settings.group.cache": "Cache", + "settings.group.views": "Views", + "settings.group.ui": "Interface", + "settings.group.diagnostics": "Diagnostics and logging", + "settings.group.advanced": "Advanced", + "settings.preset.defaults.title": "Defaults", + "settings.preset.defaults.description": "Put every mcpp setting back to its shipped default.", + "settings.preset.quiet.title": "Quiet", + "settings.preset.quiet.description": "No status-bar counters, no automatic refresh, no editor diagnostics from this extension.", + "settings.preset.everything.title": "Everything on", + "settings.preset.everything.description": "All observation and editing help enabled, including the ones that run mcpp a little more often.", + "settings.preset.diagnose.title": "Diagnose", + "settings.preset.diagnose.description": "Turn the logging up and read the C++ Modules state, for when something is wrong.", + "mcpp.toml.diagnostics.syntax.deprecationMessage": "mcpp.toml's problems come from mcpp itself now, located where mcpp reports them; this check no longer exists. mcpp.toml.diagnostics.enabled turns them all off.", + "mcpp.toml.diagnostics.unknownSection.deprecationMessage": "mcpp.toml's problems come from mcpp itself now, located where mcpp reports them; this check no longer exists. mcpp.toml.diagnostics.enabled turns them all off.", + "mcpp.toml.diagnostics.unknownKey.deprecationMessage": "mcpp.toml's problems come from mcpp itself now, located where mcpp reports them; this check no longer exists. mcpp.toml.diagnostics.enabled turns them all off.", + "mcpp.toml.diagnostics.planeSeparation.deprecationMessage": "mcpp.toml's problems come from mcpp itself now, located where mcpp reports them; this check no longer exists. mcpp.toml.diagnostics.enabled turns them all off.", + "mcpp.toml.diagnostics.legacyKeys.deprecationMessage": "mcpp.toml's problems come from mcpp itself now, located where mcpp reports them; this check no longer exists. mcpp.toml.diagnostics.enabled turns them all off." } diff --git a/spec/i18n/manifest.zh-cn.json b/spec/i18n/manifest.zh-cn.json index 7417493..61aae95 100644 --- a/spec/i18n/manifest.zh-cn.json +++ b/spec/i18n/manifest.zh-cn.json @@ -240,5 +240,28 @@ "mcpp.trust.denyEffects.title": "未受信任工作区禁止的副作用", "mcpp.trust.denyEffects.description": "工作区未受信任时 mcpp 不得做的事(mcpp --deny):需要其中之一的运行会在发生前停止并说明原因。信任工作区后解除。", "mcpp.debug.engine.title": "选择调试器", - "mcpp.debug.engine.description": "调试会话使用的调试适配器。auto:已安装 CodeLLDB 时用它,其次用 C/C++ 扩展的 gdb 或 lldb,再次用 lldb-dap。" + "mcpp.debug.engine.description": "调试会话使用的调试适配器。auto:已安装 CodeLLDB 时用它,其次用 C/C++ 扩展的 gdb 或 lldb,再次用 lldb-dap。", + "settings.group.project": "工程", + "settings.group.tasks": "任务", + "settings.group.languageService": "C++ 模块语言服务", + "settings.group.toml": "mcpp.toml 编辑", + "settings.group.buildScript": "build.mcpp 编辑", + "settings.group.cache": "缓存", + "settings.group.views": "视图", + "settings.group.ui": "界面", + "settings.group.diagnostics": "诊断与日志", + "settings.group.advanced": "高级", + "settings.preset.defaults.title": "默认", + "settings.preset.defaults.description": "把所有 mcpp 设置恢复为发布时的默认值。", + "settings.preset.quiet.title": "安静", + "settings.preset.quiet.description": "不显示状态栏计数、不自动刷新、本扩展不在编辑器中报告诊断。", + "settings.preset.everything.title": "全部开启", + "settings.preset.everything.description": "启用全部观察与编辑辅助,包括会稍多运行 mcpp 的功能。", + "settings.preset.diagnose.title": "诊断", + "settings.preset.diagnose.description": "提高日志级别并读取 C++ Modules 的状态,用于排查问题。", + "mcpp.toml.diagnostics.syntax.deprecationMessage": "mcpp.toml 的问题现在由 mcpp 自己报告并定位;这项检查已不存在。mcpp.toml.diagnostics.enabled 可整体关闭。", + "mcpp.toml.diagnostics.unknownSection.deprecationMessage": "mcpp.toml 的问题现在由 mcpp 自己报告并定位;这项检查已不存在。mcpp.toml.diagnostics.enabled 可整体关闭。", + "mcpp.toml.diagnostics.unknownKey.deprecationMessage": "mcpp.toml 的问题现在由 mcpp 自己报告并定位;这项检查已不存在。mcpp.toml.diagnostics.enabled 可整体关闭。", + "mcpp.toml.diagnostics.planeSeparation.deprecationMessage": "mcpp.toml 的问题现在由 mcpp 自己报告并定位;这项检查已不存在。mcpp.toml.diagnostics.enabled 可整体关闭。", + "mcpp.toml.diagnostics.legacyKeys.deprecationMessage": "mcpp.toml 的问题现在由 mcpp 自己报告并定位;这项检查已不存在。mcpp.toml.diagnostics.enabled 可整体关闭。" } diff --git a/src/bin/mockmcpp.cpp b/src/bin/mockmcpp.cpp index 20c0538..ff3d6f5 100644 --- a/src/bin/mockmcpp.cpp +++ b/src/bin/mockmcpp.cpp @@ -5,7 +5,8 @@ // // MCPPIDE_FIXTURES the fixtures directory (default: the repository's protocol/fixtures) // MOCK_MCPP_FAIL "build": the build fails with the compiler's diagnostic; -// "manifest": it fails on the manifest +// "manifest": it fails on the manifest (also read from the +// project's `.mock-mcpp-fail`) // MOCK_MCPP_SLOW_MS the build waits this long before it ends, so a test can // cancel it; SIGTERM then leaves the record `cancelled` // MOCK_MCPP_LOG every argv is appended here, one line each @@ -69,8 +70,18 @@ void on_term() { std::quick_exit(143); } +// The failure to play: MOCK_MCPP_FAIL, else the content of `.mock-mcpp-fail` in the project (an +// editor's test cannot change the environment of a backend it did not start). +std::string failure() { + if (auto f = env("MOCK_MCPP_FAIL"); !f.empty()) return f; + std::error_code ec; + auto text = slurp(std::filesystem::current_path(ec) / ".mock-mcpp-fail"); + while (!text.empty() && (text.back() == '\n' || text.back() == '\r')) text.pop_back(); + return text; +} + int build(bool message) { - const auto fail = env("MOCK_MCPP_FAIL"); + const auto fail = failure(); std::string stream = fixture(fail == "build" ? "build-failed.ndjson" : fail == "manifest" ? "build-manifest-error.ndjson" : "build-ok.ndjson"); std::println(std::cerr, " Compiling app v0.1.0 (.)"); @@ -109,7 +120,7 @@ int main(int argc, char** argv) { if (first(0) == "toolchain" && first(1) == "list") { std::cout << fixture("toolchain-list.json"); return 0; } if (first(0) == "cache" && first(1) == "list") { std::cout << fixture("cache-list.json"); return 0; } if (first(0) == "emit") { - if (env("MOCK_MCPP_FAIL") == "manifest") { + if (failure() == "manifest") { std::cout << replace_all(fixture("build-manifest-error.ndjson"), "\"mcpp.build\"", "\"mcpp.build-database\""); return 1; } diff --git a/src/server.cppm b/src/server.cppm index f9e8bf5..7dfd531 100644 --- a/src/server.cppm +++ b/src/server.cppm @@ -909,7 +909,10 @@ void Session::install() { auto& s = rpc_; s.on("initialize", [this](const Json& p, const rpc::Context&) { return initialize(p); }); s.on("settings/update", [this](const Json& p, const rpc::Context&) { return update_settings(p); }); - s.on("settings/registry", [](const Json&, const rpc::Context&) -> Result { return settings::registry(); }); + s.on("settings/registry", [this](const Json&, const rpc::Context&) -> Result { + std::lock_guard lock(localeMutex_); + return settings::registry(locale_); + }); s.on("settings/preset", [](const Json& p, const rpc::Context&) -> Result { auto preset = settings::preset(p.value("id", "")); if (!preset) return std::unexpected(invalid("no such preset")); diff --git a/src/settings.cppm b/src/settings.cppm index 68cfa4f..7c75d24 100644 --- a/src/settings.cppm +++ b/src/settings.cppm @@ -25,8 +25,9 @@ Checked check(const spec::Setting& s, const Json& given); // Every setting: the values to use, the rejections, and the renames an // earlier key asks for (`aliases`). Json resolve(const Json& given); -// The registry, for a settings panel: groups, entries, presets. -Json registry(); +// The registry, for a settings panel: groups, entries, presets, with the titles and descriptions +// in `locale` ("en" | "zh-cn"). +Json registry(std::string_view locale = "en"); std::optional preset(std::string_view id); } // namespace mcppide::settings @@ -102,18 +103,30 @@ Json resolve(const Json& given) { return Json{{"values", values}, {"rejected", rejected}, {"renames", renames}, {"deprecated", deprecated}}; } -Json registry() { +Json registry(std::string_view locale) { + auto text = [&](const std::string& key, const std::string& fallback) { + auto v = spec::manifest_string(key, locale); + return v == key ? fallback : v; + }; Json entries = Json::array(); for (const auto& s : spec::settings()) { Json e{{"key", s.key}, {"type", s.type}, {"default", default_of(s)}, {"group", s.group}, {"scope", s.scope}, {"applies", s.applies}, {"tier", s.tier}, {"deprecated", s.deprecated}, - {"title", s.title}, {"description", s.description}, {"expectation", expectation_of(s)}}; + {"title", text(s.key + ".title", s.title)}, {"description", text(s.key + ".description", s.description)}, + {"expectation", expectation_of(s)}}; if (s.allowed.is_array()) e["enum"] = s.allowed; if (s.minimum) e["minimum"] = *s.minimum; if (s.maximum) e["maximum"] = *s.maximum; entries.push_back(std::move(e)); } - return Json{{"settings", entries}, {"presets", spec::presets()}}; + Json groups = spec::setting_groups(); + for (auto& g : groups) g["title"] = text("settings.group." + g.value("id", ""), g.value("title", "")); + Json presets = spec::presets(); + for (auto& p : presets) { + p["title"] = text("settings.preset." + p.value("id", "") + ".title", p.value("title", "")); + p["description"] = text("settings.preset." + p.value("id", "") + ".description", p.value("description", "")); + } + return Json{{"groups", groups}, {"settings", entries}, {"presets", presets}}; } std::optional preset(std::string_view id) { diff --git a/src/spec.cppm b/src/spec.cppm index c2f53e5..cd94b4e 100644 --- a/src/spec.cppm +++ b/src/spec.cppm @@ -24,6 +24,8 @@ struct Setting { }; const std::vector& settings(); +// spec/settings.json's groups: [{id, order, title}]. +const Json& setting_groups(); const Json& presets(); // spec/presets.json's "presets" const std::map>& runtime_zh_cn(); const Json& toml_schema(); @@ -68,6 +70,11 @@ const std::vector& settings() { return all; } +const Json& setting_groups() { + static const Json g = Json::parse(generated::kSettingsJson).value("groups", Json::array()); + return g; +} + const Json& presets() { static const Json p = Json::parse(generated::kPresetsJson).value("presets", Json::array()); return p; From f28ec2b5675ca0a5dbb13014378f3780c668e88b Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Wed, 28 Oct 2026 02:42:22 +0900 Subject: [PATCH 03/30] webui: the shared panels -- project, targets and platforms, libraries, graphs, cache, pack, settings Classic scripts on one global (McppUi), loaded unchanged by a VS Code webview and a JCEF page. A panel speaks the backend's protocol through its host (rpc in, notifications out) and asks the host only for what the editor does. The graphs use a layered layout with cycle breaking and open large graphs on one node's neighbourhood. Tests: the layout, and every panel mounted in jsdom against the real backend over the mock mcpp. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- webui/index.html | 26 ++++++++ webui/js/app.js | 22 +++++++ webui/js/core.js | 84 +++++++++++++++++++++++++ webui/js/graph-layout.js | 119 +++++++++++++++++++++++++++++++++++ webui/js/host.js | 62 ++++++++++++++++++ webui/js/panels/cache.js | 72 +++++++++++++++++++++ webui/js/panels/graph.js | 113 +++++++++++++++++++++++++++++++++ webui/js/panels/libraries.js | 87 +++++++++++++++++++++++++ webui/js/panels/pack.js | 63 +++++++++++++++++++ webui/js/panels/project.js | 92 +++++++++++++++++++++++++++ webui/js/panels/settings.js | 89 ++++++++++++++++++++++++++ webui/js/panels/targets.js | 63 +++++++++++++++++++ webui/js/types.d.ts | 43 +++++++++++++ webui/styles.css | 71 +++++++++++++++++++++ webui/tests/layout.test.js | 41 ++++++++++++ webui/tests/load.js | 16 +++++ webui/tests/panels.test.js | 118 ++++++++++++++++++++++++++++++++++ webui/tsconfig.json | 14 +++++ 18 files changed, 1195 insertions(+) create mode 100644 webui/index.html create mode 100644 webui/js/app.js create mode 100644 webui/js/core.js create mode 100644 webui/js/graph-layout.js create mode 100644 webui/js/host.js create mode 100644 webui/js/panels/cache.js create mode 100644 webui/js/panels/graph.js create mode 100644 webui/js/panels/libraries.js create mode 100644 webui/js/panels/pack.js create mode 100644 webui/js/panels/project.js create mode 100644 webui/js/panels/settings.js create mode 100644 webui/js/panels/targets.js create mode 100644 webui/js/types.d.ts create mode 100644 webui/styles.css create mode 100644 webui/tests/layout.test.js create mode 100644 webui/tests/load.js create mode 100644 webui/tests/panels.test.js create mode 100644 webui/tsconfig.json diff --git a/webui/index.html b/webui/index.html new file mode 100644 index 0000000..62021e6 --- /dev/null +++ b/webui/index.html @@ -0,0 +1,26 @@ + + + + + + + + + mcpp + + +
+ + + + + + + + + + + + + diff --git a/webui/js/app.js b/webui/js/app.js new file mode 100644 index 0000000..29b04c1 --- /dev/null +++ b/webui/js/app.js @@ -0,0 +1,22 @@ +// The panel's start: tell the host it is ready, receive which panel to show and with what (the +// project root, a graph kind, a package id), the language's strings and the editor's look, then +// mount it. A later `init` replaces the panel (an editor reuses one view for several). +(function (root) { + "use strict"; + const ui = root.McppUi; + let unmount = null; + ui.on("$init", (m) => { + ui.setBundle(m.bundle || {}); + if (m.theme && typeof m.theme === "object") + for (const [k, v] of Object.entries(m.theme)) root.document.documentElement.style.setProperty(k, v); + const el = root.document.getElementById("app"); + if (typeof unmount === "function") unmount(); + ui.clear(el); + const panel = ui.panels[m.panel]; + if (!panel) { el.appendChild(ui.empty(ui.t("Unknown panel {0}", m.panel))); return; } + root.document.title = panel.title(m.params || {}); + unmount = panel.mount(el, m.params || {}) || null; + }); + if (root.document.readyState === "loading") root.document.addEventListener("DOMContentLoaded", ui.ready); + else ui.ready(); +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/core.js b/webui/js/core.js new file mode 100644 index 0000000..c68b93a --- /dev/null +++ b/webui/js/core.js @@ -0,0 +1,84 @@ +// The panels' shared helpers: the namespace, the runtime strings, formatting, and a small DOM +// builder. Classic scripts on one global (`McppUi`), so the same files load in a VS Code webview and +// in a JCEF page opened from disk, with no bundler between the repository and either editor. +(function (root) { + "use strict"; + const ui = (root.McppUi = root.McppUi || /** @type {McppUiApi} */ ({})); + ui.panels = ui.panels || {}; + + // The runtime strings: English keys, the bundle the backend answers for the session's language. + let bundle = {}; + ui.setBundle = (b) => { bundle = b && typeof b === "object" ? b : {}; }; + ui.t = (key, ...args) => { + let text = Object.prototype.hasOwnProperty.call(bundle, key) ? bundle[key] : key; + args.forEach((a, i) => { text = text.split(`{${i}}`).join(String(a)); }); + return text; + }; + + ui.formatBytes = (bytes) => { + const units = ["B", "KiB", "MiB", "GiB", "TiB"]; + let v = Math.max(0, Number(bytes) || 0); + let u = 0; + while (v >= 1024 && u + 1 < units.length) { v /= 1024; ++u; } + return u === 0 ? `${Math.round(v)} B` : `${v.toFixed(1)} ${units[u]}`; + }; + + // "3 days ago" from seconds (or milliseconds, when the value is that large) since the epoch. + ui.ago = (when, now = Date.now()) => { + if (when === undefined || when === null) return ""; + let ms = Number(when); + if (ms < 1e12) ms *= 1000; + const s = Math.max(0, Math.round((now - ms) / 1000)); + if (s < 60) return ui.t("just now"); + if (s < 3600) return ui.t("{0} min ago", Math.round(s / 60)); + if (s < 86400) return ui.t("{0} h ago", Math.round(s / 3600)); + return ui.t("{0} days ago", Math.round(s / 86400)); + }; + + ui.debounce = (fn, ms) => { + let timer; + return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); }; + }; + + // h("div.row#id", {onclick, title, ...}, children...) -- children are nodes, strings or arrays. + ui.h = (spec, props, ...children) => { + const doc = root.document; + const m = /^([a-z0-9-]+)?((?:[.#][\w-]+)*)$/i.exec(spec) || []; + const el = doc.createElement(m[1] || "div"); + for (const part of (m[2] || "").match(/[.#][\w-]+/g) || []) { + if (part[0] === ".") el.classList.add(part.slice(1)); else el.id = part.slice(1); + } + if (props && (typeof props !== "object" || props.nodeType || Array.isArray(props))) { children.unshift(props); props = null; } + for (const [k, v] of Object.entries(props || {})) { + if (v === undefined || v === null || v === false) continue; + if (k.startsWith("on") && typeof v === "function") el.addEventListener(k.slice(2), v); + else if (k === "class") el.className = v; + else if (k === "style" && typeof v === "object") Object.assign(el.style, v); + else if (k === "dataset") Object.assign(el.dataset, v); + else if (k in el && typeof v !== "string") el[k] = v; + else el.setAttribute(k, v === true ? "" : String(v)); + } + const add = (c) => { + if (c === undefined || c === null || c === false) return; + if (Array.isArray(c)) { c.forEach(add); return; } + el.appendChild(c.nodeType ? c : doc.createTextNode(String(c))); + }; + children.forEach(add); + return el; + }; + + ui.clear = (el) => { while (el.firstChild) el.removeChild(el.firstChild); return el; }; + + // A status badge: ok | warning | error | info | running. + ui.badge = (state, text) => ui.h(`span.badge.badge-${state}`, text); + + ui.button = (text, onclick, opts = {}) => + ui.h(`button${opts.secondary ? ".secondary" : ""}`, { onclick, disabled: !!opts.disabled, title: opts.title }, text); + + ui.section = (title, ...children) => ui.h("section.card", ui.h("h2", title), ...children); + + ui.empty = (text) => ui.h("p.empty", text); + + ui.errorBox = (error) => + ui.h("div.error", ui.h("strong", ui.t("mcpp could not answer")), ui.h("pre", (error && (error.message || String(error))) || "")); +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/graph-layout.js b/webui/js/graph-layout.js new file mode 100644 index 0000000..aeb8e5f --- /dev/null +++ b/webui/js/graph-layout.js @@ -0,0 +1,119 @@ +// A layered layout for the dependency graphs: every edge points from a node to one it depends on, +// layers are assigned by longest path from the roots (cycles broken at the edge that closes them), +// and the order within a layer is improved by barycentre sweeps. Pure: nodes and edges in, positions +// out; the graph panel draws them. +(function (root) { + "use strict"; + const ui = (root.McppUi = root.McppUi || /** @type {McppUiApi} */ ({})); + + // nodes: [{id}], edges: [{from, to}] -> {nodes: [{id, x, y, layer}], edges: [{from, to, points}], width, height} + function layout(nodes, edges, opts = {}) { + const nodeW = opts.nodeWidth || 180, nodeH = opts.nodeHeight || 28, gapX = opts.gapX || 24, gapY = opts.gapY || 64; + const ids = nodes.map((n) => n.id); + const index = new Map(ids.map((id, i) => [id, i])); + const out = ids.map(() => []), inn = ids.map(() => []); + const kept = []; + for (const e of edges) { + const a = index.get(e.from), b = index.get(e.to); + if (a === undefined || b === undefined || a === b) continue; + kept.push([a, b]); + } + // Break cycles: a DFS marks back edges, which are drawn but do not constrain the layers. + const state = new Array(ids.length).fill(0); + const back = new Set(); + const adj = ids.map(() => []); + kept.forEach(([a, b], k) => adj[a].push([b, k])); + for (let s = 0; s < ids.length; ++s) { + if (state[s]) continue; + const stack = [[s, 0]]; + state[s] = 1; + while (stack.length) { + const top = stack[stack.length - 1]; + const [v, i] = top; + if (i < adj[v].length) { + top[1]++; + const [w, k] = adj[v][i]; + if (state[w] === 1) back.add(k); + else if (state[w] === 0) { state[w] = 1; stack.push([w, 0]); } + } else { state[v] = 2; stack.pop(); } + } + } + kept.forEach(([a, b], k) => { if (!back.has(k)) { out[a].push(b); inn[b].push(a); } }); + // Longest path from the roots (nodes nothing depends on): a dependency sits below its users. + const layer = new Array(ids.length).fill(0); + const indeg = inn.map((l) => l.length); + const queue = []; + indeg.forEach((d, i) => { if (d === 0) queue.push(i); }); + for (let q = 0; q < queue.length; ++q) { + const v = queue[q]; + for (const w of out[v]) { + layer[w] = Math.max(layer[w], layer[v] + 1); + if (--indeg[w] === 0) queue.push(w); + } + } + const layers = []; + layer.forEach((l, i) => { (layers[l] = layers[l] || []).push(i); }); + for (let l = 0; l < layers.length; ++l) if (!layers[l]) layers[l] = []; + // Barycentre sweeps, down then up. + const pos = new Array(ids.length).fill(0); + const place = () => layers.forEach((row) => row.forEach((v, i) => { pos[v] = i; })); + place(); + const sweep = (rows, neighbours) => { + for (const row of rows) { + const key = new Map(row.map((v) => { + const ns = neighbours[v]; + return [v, ns.length ? ns.reduce((s, w) => s + pos[w], 0) / ns.length : pos[v]]; + })); + row.sort((a, b) => key.get(a) - key.get(b) || a - b); + row.forEach((v, i) => { pos[v] = i; }); + } + }; + for (let k = 0; k < (opts.sweeps || 4); ++k) { + sweep(layers.slice(1), inn); + sweep(layers.slice(0, -1).reverse(), out); + } + const widest = Math.max(1, ...layers.map((r) => r.length)); + const width = widest * (nodeW + gapX) + gapX; + const placed = nodes.map((n, i) => { + const row = layers[layer[i]]; + const offset = (width - row.length * (nodeW + gapX) - gapX) / 2; + return Object.assign({}, n, { + layer: layer[i], + x: offset + gapX + pos[i] * (nodeW + gapX), + y: gapY / 2 + layer[i] * (nodeH + gapY), + width: nodeW, + height: nodeH, + }); + }); + const routed = kept.map(([a, b], k) => { + const p = placed[a], q = placed[b]; + return { + from: ids[a], to: ids[b], back: back.has(k), + points: [[p.x + nodeW / 2, p.y + nodeH], [q.x + nodeW / 2, q.y]], + }; + }); + return { nodes: placed, edges: routed, width, height: layers.length * (nodeH + gapY) + gapY / 2 }; + } + + // The part of a graph around one node: it, what it depends on and what depends on it, `depth` + // steps each way. Large module graphs are read this way rather than all at once. + function neighbourhood(nodes, edges, focus, depth = 1) { + const keep = new Set([focus]); + let frontier = new Set([focus]); + for (let d = 0; d < depth; ++d) { + const next = new Set(); + for (const e of edges) { + if (frontier.has(e.from) && !keep.has(e.to)) next.add(e.to); + if (frontier.has(e.to) && !keep.has(e.from)) next.add(e.from); + } + next.forEach((v) => keep.add(v)); + frontier = next; + } + return { + nodes: nodes.filter((n) => keep.has(n.id)), + edges: edges.filter((e) => keep.has(e.from) && keep.has(e.to)), + }; + } + + ui.graphLayout = { layout, neighbourhood }; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/host.js b/webui/js/host.js new file mode 100644 index 0000000..315b7df --- /dev/null +++ b/webui/js/host.js @@ -0,0 +1,62 @@ +// The bridge to the editor that hosts the panel. The panel speaks the backend's protocol through +// it (`rpc`), receives the backend's notifications (`on`), and asks the editor for what only the +// editor can do (`host`: open a file, confirm, write a setting, start a terminal). +// +// VS Code: `acquireVsCodeApi().postMessage` out, `window` "message" events in. +// JetBrains (JCEF): `window.mcppHostSend(text)` out (a JBCefJSQuery the plugin injects), and the +// plugin calls `window.mcppHostReceive(message)` in. +(function (root) { + "use strict"; + const ui = (root.McppUi = root.McppUi || /** @type {McppUiApi} */ ({})); + let send; + const vscode = typeof root.acquireVsCodeApi === "function" ? root.acquireVsCodeApi() : undefined; + if (vscode) send = (m) => vscode.postMessage(m); + else send = (m) => { if (typeof root.mcppHostSend === "function") root.mcppHostSend(JSON.stringify(m)); else queue.push(m); }; + const queue = []; + let nextId = 1; + const pending = new Map(); + const listeners = new Map(); + + function receive(m) { + if (typeof m === "string") { try { m = JSON.parse(m); } catch { return; } } + if (!m || typeof m !== "object") return; + if (m.type === "rpcResult" || m.type === "hostResult") { + const p = pending.get(m.id); pending.delete(m.id); + if (p) p.resolve(m.result); + } else if (m.type === "rpcError" || m.type === "hostError") { + const p = pending.get(m.id); pending.delete(m.id); + if (p) p.reject(Object.assign(new Error((m.error && m.error.message) || "failed"), { data: m.error && m.error.data, code: m.error && m.error.code })); + } else if (m.type === "notify") { + for (const fn of listeners.get(m.method) || []) fn(m.params); + for (const fn of listeners.get("*") || []) fn(m.method, m.params); + } else if (m.type === "init") { + for (const fn of listeners.get("$init") || []) fn(m); + } + } + if (vscode) root.addEventListener("message", (e) => receive(e.data)); + root.mcppHostReceive = receive; + // The JCEF query is injected after the page loads: whatever was sent before it goes then. + root.mcppHostAttached = () => { while (queue.length) send(queue.shift()); }; + + function request(type, fields) { + const id = nextId++; + return new Promise((resolve, reject) => { + pending.set(id, { resolve, reject }); + send(Object.assign({ type, id }, fields)); + }); + } + + ui.rpc = (method, params = {}) => request("rpc", { method, params }); + ui.host = (action, params = {}) => request("host", { action, params }); + ui.on = (method, fn) => { + if (!listeners.has(method)) listeners.set(method, new Set()); + listeners.get(method).add(fn); + return () => listeners.get(method).delete(fn); + }; + ui.ready = () => send({ type: "ready" }); + ui.state = { + get: () => (vscode ? vscode.getState() : root.__mcppState) || {}, + set: (s) => { if (vscode) vscode.setState(s); else root.__mcppState = s; }, + }; + ui.editor = vscode ? "vscode" : "jetbrains"; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/panels/cache.js b/webui/js/panels/cache.js new file mode 100644 index 0000000..6337ac7 --- /dev/null +++ b/webui/js/panels/cache.js @@ -0,0 +1,72 @@ +// The cache panel: what mcpp's shared build cache holds (`mcpp cache list`), by kind, by package and +// by age, and the cleanups. A cleanup is a plan the backend makes (its argv, its danger level, its +// preview); the editor confirms it natively, at the level the plan asks for. +(function (root) { + "use strict"; + const ui = root.McppUi; + const { h, t } = ui; + + // plan -> preview -> the editor's confirmation -> apply. Used by the panel and nothing else: the + // editors' own commands run the same three steps against the same plan. + async function cleanup(action, rootDir) { + const plan = await ui.rpc("cache/plan", { action, root: rootDir }); + if (plan.refusedUntrusted) { + await ui.host("notify", { level: "warning", message: t("this action needs a trusted workspace") }); + return false; + } + let confirmation = {}; + if (plan.level > 0) { + let preview = ""; + if (plan.preview && plan.preview.source === "mcpp") preview = plan.preview.text || ""; + else if (plan.preview && plan.preview.entries) + preview = t("About {0} would be freed ({1} entries).", plan.preview.bytesText, plan.preview.count); + const answer = await ui.host("confirm", { title: plan.title, detail: plan.detail, preview, level: plan.level, acknowledge: plan.acknowledge }); + if (!answer || !answer.confirmed) return false; + confirmation = { confirmed: true, previewShown: !!plan.preview, acknowledged: !!answer.acknowledged }; + } + await ui.rpc("cache/apply", { action, root: rootDir, confirmation }); + return true; + } + ui.cleanup = cleanup; + + function bars(rows, total, label) { + return h("table.bars", rows.map((r) => h("tr", + h("td", label(r)), + h("td.num", ui.formatBytes(r.bytes)), + h("td.bar", h("div", { style: { width: `${total ? Math.max(1, Math.round((100 * r.bytes) / total)) : 0}%` } }))))); + } + + ui.panels.cache = { + title: () => t("Cache"), + mount(el, params) { + const rootDir = params.root; + async function render() { + ui.clear(el).appendChild(h("p.muted", t("Loading…"))); + let inv; + try { inv = await ui.rpc("cache/inventory", { root: rootDir }); } catch (e) { ui.clear(el).appendChild(ui.errorBox(e)); return; } + ui.clear(el); + el.append( + h("header.panel-head", + h("h1", t("Cache")), + h("p", h("strong", inv.totalText), " ", t("in {0} entries", inv.totalEntries), inv.root ? h("span.muted", ` · ${inv.root}`) : null), + h("div.actions", ui.button(t("Refresh"), render, { secondary: true }))), + ui.section(t("By kind"), bars(inv.byKind, inv.totalBytes, (r) => `${r.kind} (${r.entries})`)), + ui.section(t("Largest packages"), inv.topLabels.length ? bars(inv.topLabels, inv.totalBytes, (r) => r.label) : ui.empty(t("none"))), + ui.section(t("By last use"), bars(inv.ageBuckets, inv.totalBytes, (b) => + b.toDays === undefined ? t("older than {0} days", b.fromDays) : t("{0}–{1} days", b.fromDays, b.toDays))), + inv.incomplete.length ? ui.section(t("Incomplete entries"), h("ul.list", inv.incomplete.map((e) => h("li", e.label || e.key)))) : null, + ui.section(t("Clean up"), + h("div.actions.wrap", + [["stale", t("Clean stale artifacts")], ["project", t("Clean project artifacts")], ["cacheGc", t("Collect to a budget")], + ["cachePrune", t("Prune by age")], ["cacheDeps", t("Drop package entries")], ["cacheStd", t("Drop standard library entries")], + ["cacheVerify", t("Verify")], ["cacheLegacy", t("Remove the pre-v1 cache")], ["cacheAll", t("Drop everything")]] + .map(([action, label]) => ui.button(label, async () => { + try { if (await cleanup(action, rootDir)) setTimeout(render, 500); } catch (e) { el.prepend(ui.errorBox(e)); } + }, { secondary: action !== "stale", disabled: action === "project" && !rootDir }))))); + } + const off = ui.on("job/finished", (p) => { if (p.kind === "clean" || p.kind === "command") render(); }); + render(); + return off; + }, + }; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/panels/graph.js b/webui/js/panels/graph.js new file mode 100644 index 0000000..88ce573 --- /dev/null +++ b/webui/js/panels/graph.js @@ -0,0 +1,113 @@ +// The dependency graphs: packages (which set sees which) and modules (who provides, who imports), +// from mcpp's build database through the backend's view models. Drawn as SVG with a layered layout; +// a large graph opens on the neighbourhood of one node, chosen by search or by a click. +(function (root) { + "use strict"; + const ui = root.McppUi; + const { h, t } = ui; + const SVG = "http://www.w3.org/2000/svg"; + const svg = (tag, attrs = {}, ...children) => { + const el = root.document.createElementNS(SVG, tag); + for (const [k, v] of Object.entries(attrs)) el.setAttribute(k, String(v)); + children.forEach((c) => c && el.appendChild(c)); + return el; + }; + // Beyond this many nodes the whole graph is shown only when asked for. + const WHOLE_LIMIT = 150; + + ui.panels.graph = { + title: (params) => (params.graph === "modules" ? t("Module graph") : t("Dependency graph")), + mount(el, params) { + const kind = params.graph === "modules" ? "modules" : "packages"; + const rootDir = params.root; + let data = { nodes: [], edges: [] }; + let focus = null, depth = 1, whole = false; + let zoom = 1, panX = 0, panY = 0; + const search = h("input", { type: "search", placeholder: t("Find a node") }); + const list = h("datalist#graph-nodes"); + search.setAttribute("list", "graph-nodes"); + const depthSel = h("select", [1, 2, 3].map((d) => h("option", { value: d }, t("{0} step(s) around", d)))); + const canvas = h("div.graph-canvas"); + const status = h("p.muted"); + + function draw() { + ui.clear(canvas); + let view = data; + if (focus) view = ui.graphLayout.neighbourhood(data.nodes, data.edges, focus, depth); + else if (data.nodes.length > WHOLE_LIMIT && !whole) { + status.textContent = t("{0} nodes: choose one to see its neighbourhood, or show the whole graph.", data.nodes.length); + canvas.appendChild(h("div.actions", ui.button(t("Show the whole graph"), () => { whole = true; draw(); }, { secondary: true }))); + return; + } + status.textContent = focus ? t("{0} and {1} node(s) around it", focus, view.nodes.length - 1) + : t("{0} nodes, {1} edges", view.nodes.length, view.edges.length); + const lay = ui.graphLayout.layout(view.nodes, view.edges, { nodeWidth: kind === "modules" ? 200 : 180 }); + const g = svg("g"); + const defs = svg("defs", {}, svg("marker", { id: "arrow", viewBox: "0 0 10 10", refX: 9, refY: 5, markerWidth: 6, markerHeight: 6, orient: "auto-start-reverse" }, + svg("path", { d: "M 0 0 L 10 5 L 0 10 z", class: "arrow" }))); + for (const e of lay.edges) { + const [[x1, y1], [x2, y2]] = e.points; + const my = (y1 + y2) / 2; + g.appendChild(svg("path", { d: `M ${x1} ${y1} C ${x1} ${my}, ${x2} ${my}, ${x2} ${y2}`, class: e.back ? "edge back" : "edge", "marker-end": "url(#arrow)" })); + } + for (const n of lay.nodes) { + const label = n.id.length > 28 ? `${n.id.slice(0, 26)}…` : n.id; + const node = svg("g", { class: `node kind-${n.kind || "set"}${n.id === focus ? " focus" : ""}`, transform: `translate(${n.x},${n.y})`, tabindex: 0 }, + svg("rect", { width: n.width, height: n.height, rx: 4 }), + svg("text", { x: 8, y: n.height / 2 + 4 }, root.document.createTextNode(label))); + const title = svg("title"); + title.textContent = [n.id, n.source || "", n.set ? `(${n.set})` : ""].filter(Boolean).join("\n"); + node.appendChild(title); + node.addEventListener("click", () => { focus = n.id; draw(); }); + node.addEventListener("dblclick", () => { if (n.source) ui.host("openFile", { path: n.source }); }); + node.addEventListener("keydown", (ev) => { if (ev.key === "Enter") { focus = n.id; draw(); } }); + g.appendChild(node); + } + const s = svg("svg", { width: "100%", height: "100%" }, defs, g); + const apply = () => g.setAttribute("transform", `translate(${panX},${panY}) scale(${zoom})`); + zoom = Math.min(1, (canvas.clientWidth || 800) / lay.width, (canvas.clientHeight || 600) / lay.height) || 1; + panX = Math.max(0, ((canvas.clientWidth || 800) - lay.width * zoom) / 2); panY = 8; + apply(); + s.addEventListener("wheel", (ev) => { + ev.preventDefault(); + const next = Math.max(0.05, Math.min(4, zoom * (ev.deltaY < 0 ? 1.1 : 1 / 1.1))); + const r = s.getBoundingClientRect(), x = ev.clientX - r.left, y = ev.clientY - r.top; + panX = x - ((x - panX) * next) / zoom; panY = y - ((y - panY) * next) / zoom; zoom = next; apply(); + }, { passive: false }); + let drag = null; + s.addEventListener("pointerdown", (ev) => { if (ev.target === s) { drag = [ev.clientX - panX, ev.clientY - panY]; s.setPointerCapture(ev.pointerId); } }); + s.addEventListener("pointermove", (ev) => { if (drag) { panX = ev.clientX - drag[0]; panY = ev.clientY - drag[1]; apply(); } }); + s.addEventListener("pointerup", () => { drag = null; }); + canvas.appendChild(s); + } + + async function load() { + status.textContent = t("Loading…"); + try { data = await ui.rpc(kind === "modules" ? "graph/modules" : "graph/packages", { root: rootDir }); } + catch (e) { status.textContent = ""; ui.clear(canvas).appendChild(ui.errorBox(e)); return; } + ui.clear(list); + data.nodes.forEach((n) => list.appendChild(h("option", { value: n.id }))); + if (params.focus) focus = params.focus; + draw(); + } + search.addEventListener("change", () => { if (data.nodes.some((n) => n.id === search.value)) { focus = search.value; draw(); } }); + depthSel.addEventListener("change", () => { depth = Number(depthSel.value); draw(); }); + el.append( + h("header.panel-head", + h("h1", kind === "modules" ? t("Module graph") : t("Dependency graph")), + h("div.toolbar", search, list, depthSel, + ui.button(t("Overview"), () => { focus = null; draw(); }, { secondary: true }), + ui.button(t("Refresh"), load, { secondary: true }), + ui.button(t("Copy as Mermaid"), () => { + const lines = ["graph TD"]; + data.edges.forEach((e) => lines.push(` ${JSON.stringify(e.from)} --> ${JSON.stringify(e.to)}`.replace(/"/g, ""))); + ui.host("copy", { text: lines.join("\n") }); + }, { secondary: true })), + status), + canvas); + const off = ui.on("result/changed", (p) => { if (p.root === rootDir) load(); }); + load(); + return off; + }, + }; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/panels/libraries.js b/webui/js/panels/libraries.js new file mode 100644 index 0000000..71f54f8 --- /dev/null +++ b/webui/js/panels/libraries.js @@ -0,0 +1,87 @@ +// The libraries panel: the packages of every index mcpp reads (`mcpp search`), filtered and sorted +// by the backend, and one package's page. "Add" runs `mcpp add` on the project, which writes +// mcpp.toml; nothing here edits the manifest itself. +(function (root) { + "use strict"; + const ui = root.McppUi; + const { h, t } = ui; + + function detail(el, pkg, rootDir, back) { + ui.clear(el); + const versions = pkg.versions || []; + const select = h("select", versions.map((v) => h("option", { value: v }, v))); + el.append( + h("header.panel-head", + h("a.back", { href: "#", onclick: (e) => { e.preventDefault(); back(); } }, `← ${t("All packages")}`), + h("h1", pkg.id), + h("p", pkg.description || ""), + h("dl.facts", + h("dt", t("Index")), h("dd", pkg.index || ""), + h("dt", t("Dependency name")), h("dd", h("code", pkg.dependencyName || pkg.name)), + h("dt", t("Licences")), h("dd", (pkg.licenses || []).join(", ") || "—"), + pkg.repo ? [h("dt", t("Repository")), h("dd", h("a", { href: "#", onclick: (e) => { e.preventDefault(); ui.host("openExternal", { url: pkg.repo }); } }, pkg.repo))] : null), + h("div.actions", + select, + ui.button(t("Add to mcpp.toml"), async () => { + if (!rootDir) { await ui.host("notify", { level: "warning", message: t("No mcpp project in this workspace") }); return; } + await ui.rpc("library/add", { root: rootDir, dependency: pkg.dependencyName || pkg.name, version: select.value }); + }, { disabled: !rootDir }))), + ui.section(t("Versions"), h("ul.list", versions.map((v) => h("li", h("code", v)))))); + } + + ui.panels.libraries = { + title: () => t("Libraries"), + mount(el, params) { + const rootDir = params.root; + const saved = ui.state.get().libraries || {}; + const search = h("input", { type: "search", placeholder: t("Search packages"), value: saved.keyword || "" }); + const sort = h("select", h("option", { value: "name" }, t("by name")), h("option", { value: "versions" }, t("by versions"))); + sort.value = saved.sort || "name"; + const index = h("select", h("option", { value: "" }, t("every index"))); + const results = h("div.results"); + const status = h("p.muted"); + let lastQuery = 0; + + async function query(refresh = false) { + const id = ++lastQuery; + ui.state.set(Object.assign(ui.state.get(), { libraries: { keyword: search.value, sort: sort.value } })); + status.textContent = t("Searching…"); + let r; + try { + r = await ui.rpc("library/search", { keyword: search.value, sort: sort.value, index: index.value, limit: 300, refresh, root: rootDir }); + } catch (e) { + if (id === lastQuery) { status.textContent = ""; ui.clear(results).appendChild(ui.errorBox(e)); } + return; + } + if (id !== lastQuery) return; + if (index.options.length === 1) for (const name of r.indexes || []) index.appendChild(h("option", { value: name }, name)); + status.textContent = t("{0} packages", r.total); + ui.clear(results); + if (!r.packages.length) { results.appendChild(ui.empty(t("No package matches."))); return; } + results.appendChild(h("ul.list.packages", r.packages.map((p) => + h("li.package", { onclick: () => detail(el, p, rootDir, () => { ui.clear(el); mountList(); }) }, + h("div", h("strong", p.id), h("span.muted", ` ${p.latest || ""}`)), + h("div.muted", p.description || ""))))); + } + + function mountList() { + el.append( + h("header.panel-head", + h("h1", t("Libraries")), + h("div.toolbar", search, sort, index, + ui.button(t("Refresh the index"), async () => { await ui.rpc("library/updateIndex", { root: rootDir }); }, { secondary: true }))), + status, results); + query(); + } + search.addEventListener("input", ui.debounce(() => query(), 200)); + sort.addEventListener("change", () => query()); + index.addEventListener("change", () => query()); + const off = ui.on("job/finished", (p) => { if ((p.envelope && p.envelope.kind) || p.kind === "command") query(true); }); + if (params.id) { + ui.rpc("library/search", { id: params.id, root: rootDir }).then((p) => detail(el, p, rootDir, () => { ui.clear(el); mountList(); }), + (e) => el.appendChild(ui.errorBox(e))); + } else mountList(); + return off; + }, + }; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/panels/pack.js b/webui/js/panels/pack.js new file mode 100644 index 0000000..dc8b007 --- /dev/null +++ b/webui/js/panels/pack.js @@ -0,0 +1,63 @@ +// The pack panel: the formats mcpp can produce for this project (`mcpp pack --list-formats`, with +// the plugins that provide them), the mode, the target, and the result of a pack: what was written +// and where. +(function (root) { + "use strict"; + const ui = root.McppUi; + const { h, t } = ui; + + ui.panels.pack = { + title: () => t("Pack"), + mount(el, params) { + const rootDir = params.root; + const format = h("select"); + const mode = h("select", ["", "static", "bundle-project", "bundle-all", "self-contained"].map((m) => + h("option", { value: m }, m || t("the project's default")))); + const profile = h("select", ["release", "dev"].map((p) => h("option", { value: p }, p))); + const target = h("input", { type: "text", placeholder: t("this machine") }); + const output = h("pre.log"); + const result = h("div"); + let jobId = null; + const go = ui.button(t("Pack"), async () => { + ui.clear(output); ui.clear(result); + try { + const r = await ui.rpc("pack/start", { root: rootDir, format: format.value || undefined, mode: mode.value || undefined, + profile: profile.value, target: target.value }); + jobId = r.jobId; go.disabled = true; + } catch (e) { result.appendChild(ui.errorBox(e)); } + }); + const offs = [ + ui.on("job/output", (p) => { if (p.jobId === jobId) output.textContent += p.text; }), + ui.on("job/finished", (p) => { + if (p.jobId !== jobId) return; + go.disabled = false; jobId = null; + ui.clear(result); + const data = (p.envelope && p.envelope.data) || {}; + result.appendChild(ui.section(t("Result"), + h("p", ui.badge(p.status === "ok" ? "ok" : "error", p.status)), + (p.diagnostics || []).map((d) => h("p.error", d.message)), + data.outputs || data.artifacts ? h("ul.list", (data.outputs || data.artifacts).map((o) => { + const path = typeof o === "string" ? o : o.path; + return h("li", h("code", path), ui.button(t("Reveal"), () => ui.host("reveal", { path }), { secondary: true })); + })) : h("pre", JSON.stringify(data, null, 2)))); + }), + ]; + el.append(h("header.panel-head", h("h1", t("Pack")), h("p.muted", rootDir || "")), + ui.section(t("What to produce"), + h("dl.facts", + h("dt", t("Format")), h("dd", format), + h("dt", t("Mode")), h("dd", mode), + h("dt", t("Profile")), h("dd", profile), + h("dt", t("Target")), h("dd", target)), + h("div.actions", go)), + result, output); + ui.rpc("pack/formats", { root: rootDir }).then((r) => { + format.appendChild(h("option", { value: "" }, t("the project's default"))); + for (const f of (r && r.formats) || []) + format.appendChild(h("option", { value: f.name }, f.builtin ? f.name : `${f.name} (${(f.providers || []).join(", ")})`)); + }, (e) => result.appendChild(ui.errorBox(e))); + ui.host("settings", {}).then((s) => { if (s && s["mcpp.build.target"]) target.value = s["mcpp.build.target"]; }); + return () => offs.forEach((off) => off()); + }, + }; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/panels/project.js b/webui/js/panels/project.js new file mode 100644 index 0000000..f623a91 --- /dev/null +++ b/webui/js/panels/project.js @@ -0,0 +1,92 @@ +// The project panel: what the project builds (executables, tests, libraries), for which target and +// platform, how its last build went, and the language service that answers its sources. The actions +// are the command table's: the editor runs them as it runs the same commands from its menus. +(function (root) { + "use strict"; + const ui = root.McppUi; + const { h, t } = ui; + + function languageServiceCard(status, refresh) { + if (!status) return null; + const state = status.state === "ok" ? "ok" : status.state === "missing" ? "error" : "warning"; + return ui.section( + t("C++ Modules language service"), + h("p", ui.badge(state, status.state === "ok" ? `mcppls ${status.version}` : t("needs attention")), " ", status.message), + h("div.actions", + (status.actions || []).map((a) => ui.button(a.title, () => ui.host("languageService", { action: a.id }))), + ui.button(t("Check again"), refresh, { secondary: true }))); + } + + function list(title, rows, render) { + return ui.section(`${title} (${rows.length})`, rows.length ? h("ul.list", rows.map(render)) : ui.empty(t("none"))); + } + + ui.panels.project = { + title: () => t("Project"), + mount(el, params) { + const rootDir = params.root; + let jobRunning = null; + const command = (id) => () => ui.host("runCommand", { command: id, root: rootDir }); + + async function render() { + ui.clear(el); + if (!rootDir) { el.appendChild(ui.empty(t("No mcpp project in this workspace"))); return; } + el.appendChild(h("p.muted", t("Loading…"))); + let summary, ls; + try { + [summary, ls] = await Promise.all([ui.rpc("project/summary", { root: rootDir }), ui.rpc("languageService/status", {})]); + } catch (e) { + ui.clear(el).appendChild(ui.errorBox(e)); + return; + } + ui.clear(el); + const name = rootDir.split(/[\\/]/).filter(Boolean).pop(); + const target = summary.target || ""; + el.appendChild(h("header.panel-head", + h("h1", name), + h("p.muted", rootDir), + h("div.actions", + ui.button(t("Build"), command("mcpp.build"), { disabled: !!jobRunning }), + ui.button(t("Run"), command("mcpp.run")), + ui.button(t("Debug"), command("mcpp.debug")), + ui.button(t("Test"), command("mcpp.test"), { disabled: !!jobRunning }), + ui.button(t("Pack"), () => ui.host("openPanel", { panel: "pack", root: rootDir }), { secondary: true }), + ui.button(t("Clean target"), command("mcpp.clean"), { secondary: true }), + jobRunning ? ui.button(t("Cancel"), () => ui.rpc("job/cancel", { jobId: jobRunning }), { secondary: true }) : null))); + + const facts = h("dl.facts", + h("dt", t("Target")), h("dd", target || t("this machine"), " ", ui.h("a", { href: "#", onclick: (e) => { e.preventDefault(); ui.host("openPanel", { panel: "targets", root: rootDir }); } }, t("change"))), + h("dt", t("Platform")), h("dd", summary.platformText || t("reported after the first build")), + summary.hostPlatformText ? [h("dt", t("Host platform")), h("dd", summary.hostPlatformText)] : null, + h("dt", t("Toolchain")), h("dd", summary.toolchain || "—")); + if (summary.lastBuild) { + const b = summary.lastBuild; + facts.append(h("dt", t("Last build")), + h("dd", ui.badge(b.status === "ok" ? "ok" : b.status === "cancelled" ? "info" : "error", b.status), " ", + ui.ago(b.finishedAt), b.client ? ` · ${b.client}` : "")); + } + el.appendChild(ui.section(t("Overview"), facts, summary.error ? ui.errorBox({ message: summary.error }) : null)); + el.appendChild(list(t("Executables"), summary.targets || [], (r) => + h("li", h("span", r.name), h("span.muted", r.configuration || "")))); + el.appendChild(list(t("Tests"), summary.tests || [], (r) => + h("li", h("span", r.name), ui.button(t("Run"), () => ui.host("runCommand", { command: "mcpp.test", root: rootDir, args: { filter: r.name } }), { secondary: true })))); + el.appendChild(list(t("Libraries"), summary.libraries || [], (r) => h("li", h("span", r.name), h("span.muted", r.kind)))); + el.appendChild(h("div.actions", + ui.button(t("Dependency graph"), () => ui.host("openPanel", { panel: "graph", root: rootDir, graph: "packages" }), { secondary: true }), + ui.button(t("Module graph"), () => ui.host("openPanel", { panel: "graph", root: rootDir, graph: "modules" }), { secondary: true }), + ui.button(t("Libraries"), () => ui.host("openPanel", { panel: "libraries", root: rootDir }), { secondary: true }))); + const card = languageServiceCard(ls, render); + if (card) el.appendChild(card); + } + + const offs = [ + ui.on("job/started", (p) => { if (p.root === rootDir) { jobRunning = p.jobId; render(); } }), + ui.on("job/finished", (p) => { if (p.root === rootDir || p.jobId === jobRunning) { jobRunning = null; render(); } }), + ui.on("result/changed", (p) => { if (p.root === rootDir) render(); }), + ui.on("manifest/changed", (p) => { if (p.root === rootDir) render(); }), + ]; + render(); + return () => offs.forEach((off) => off()); + }, + }; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/panels/settings.js b/webui/js/panels/settings.js new file mode 100644 index 0000000..921d2b4 --- /dev/null +++ b/webui/js/panels/settings.js @@ -0,0 +1,89 @@ +// The settings panel: every setting of the registry (spec/settings.json), grouped, with what it +// takes; a change is written by the editor into its own settings store, and the backend's resolution +// (rejections, renamed keys) is shown beside it. Presets apply several at once. +(function (root) { + "use strict"; + const ui = root.McppUi; + const { h, t } = ui; + + function control(entry, value, write) { + if (entry.type === "boolean") + return h("input", { type: "checkbox", checked: !!value, onchange: (e) => write(e.target.checked) }); + if (entry.enum) + return h("select", { onchange: (e) => write(e.target.value) }, entry.enum.map((v) => h("option", { value: v, selected: v === value }, v))); + if (entry.type === "number") + return h("input", { type: "number", value: value ?? "", min: entry.minimum, max: entry.maximum, onchange: (e) => write(Number(e.target.value)) }); + if (entry.type === "array") + return h("textarea", { rows: 2, placeholder: t("one per line"), onchange: (e) => write(e.target.value.split("\n").map((s) => s.trim()).filter(Boolean)) }, + (value || []).join("\n")); + return h("input", { type: "text", value: value ?? "", onchange: (e) => write(e.target.value) }); + } + + ui.panels.settings = { + title: () => t("Settings"), + mount(el) { + const filter = h("input", { type: "search", placeholder: t("Filter settings") }); + const advanced = h("input", { type: "checkbox" }); + const body = h("div"); + let registry, values = {}, resolved = {}; + + async function load() { + ui.clear(body).appendChild(h("p.muted", t("Loading…"))); + try { + [registry, values] = await Promise.all([ui.rpc("settings/registry", {}), ui.host("settings", {})]); + resolved = await ui.rpc("settings/update", { settings: values }); + } catch (e) { ui.clear(body).appendChild(ui.errorBox(e)); return; } + draw(); + } + + function draw() { + ui.clear(body); + const needle = filter.value.toLowerCase(); + const rejected = new Map((resolved.rejected || []).map((r) => [r.key, r])); + const groups = new Map(); + for (const s of registry.settings) { + if (s.tier === "advanced" && !advanced.checked) continue; + if (needle && !`${s.key} ${s.title} ${s.description}`.toLowerCase().includes(needle)) continue; + if (!groups.has(s.group)) groups.set(s.group, []); + groups.get(s.group).push(s); + } + if ((resolved.renames || []).length) + body.appendChild(ui.section(t("Renamed settings"), + h("ul.list", resolved.renames.map((r) => h("li", h("code", r.from), " → ", h("code", r.to)))), + ui.button(t("Move them"), async () => { await ui.host("migrateSettings", { renames: resolved.renames }); load(); }))); + const groupTitle = new Map((registry.groups || []).map((g) => [g.id, g.title])); + for (const [group, entries] of groups) { + body.appendChild(ui.section(groupTitle.get(group) || group, entries.map((s) => { + const value = Object.prototype.hasOwnProperty.call(values, s.key) ? values[s.key] : s.default; + const bad = rejected.get(s.key); + return h("div.setting", + h("label", h("strong", s.title || s.key), h("code.muted", ` ${s.key}`)), + h("p.muted", s.description), + control(s, value, async (v) => { + await ui.host("setSetting", { key: s.key, value: v }); + values[s.key] = v; + resolved = await ui.rpc("settings/update", { settings: values }); + draw(); + }), + s.applies === "restart" ? h("p.note", t("Takes effect after a restart.")) : null, + bad ? h("p.error", t("Not accepted ({0}); expected {1}. The default is used.", bad.reason, bad.expectation)) : null); + }))); + } + if ((registry.presets || []).length) + body.appendChild(ui.section(t("Presets"), h("div.actions.wrap", registry.presets.map((p) => + ui.button(p.title || p.id, async () => { + const preset = await ui.rpc("settings/preset", { id: p.id }); + const entries = Object.entries(preset.values || {}); + // An empty preset is every setting at its default. + if (!entries.length) await ui.host("resetSettings", { keys: registry.settings.map((s) => s.key) }); + for (const [k, v] of entries) await ui.host("setSetting", { key: k, value: v }); + load(); + }, { secondary: true, title: p.description || "" }))))); + } + filter.addEventListener("input", ui.debounce(draw, 150)); + advanced.addEventListener("change", draw); + el.append(h("header.panel-head", h("h1", t("Settings")), h("div.toolbar", filter, h("label", advanced, ` ${t("Show advanced settings")}`))), body); + load(); + }, + }; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/panels/targets.js b/webui/js/panels/targets.js new file mode 100644 index 0000000..3b0cf5d --- /dev/null +++ b/webui/js/panels/targets.js @@ -0,0 +1,63 @@ +// The targets panel: every target mcpp knows, the toolchains installed for it, and the platform +// that configures it (mcpp's platforms: a built-in convention, a pinned platform package, or one the +// project or this machine chose), with each of the platform's fields and where its value came from. +// Choosing a target writes `mcpp.build.target`; build, run, test, debug and pack then use it. +(function (root) { + "use strict"; + const ui = root.McppUi; + const { h, t } = ui; + + function fields(platform) { + const f = (platform && platform.fields) || {}; + const keys = Object.keys(f); + if (!keys.length) return null; + return h("table.fields", keys.map((k) => { + const v = f[k] && Object.prototype.hasOwnProperty.call(f[k], "value") ? f[k].value : f[k]; + return h("tr", h("td", h("code", k)), h("td", typeof v === "string" ? v : JSON.stringify(v)), h("td.muted", (f[k] && f[k].source) || "")); + })); + } + + ui.panels.targets = { + title: () => t("Targets and Platforms"), + mount(el, params) { + const rootDir = params.root; + async function render() { + ui.clear(el).appendChild(h("p.muted", t("Loading…"))); + let r; + try { r = await ui.rpc("targets/list", { root: rootDir }); } catch (e) { ui.clear(el).appendChild(ui.errorBox(e)); return; } + ui.clear(el); + el.appendChild(h("header.panel-head", + h("h1", t("Targets and Platforms")), + h("p", t("This machine: {0}", r.host), r.hostPlatformText ? h("span.muted", ` · ${t("host platform")}: ${r.hostPlatformText}`) : null), + r.lastPlan && r.lastPlan.configuration ? h("p.muted", t("Last build: {0}, {1}", r.lastPlan.configuration.triple, r.lastPlan.platformText || t("host conventions"))) : null)); + const rows = r.rows.map((row) => { + const details = h("details", + h("summary", row.platformText || t("platform not reported by this mcpp")), + fields(row.platform) || h("p.muted", t("No platform fields reported."))); + const choose = row.selected ? ui.badge("ok", t("selected")) + : ui.button(t("Use"), async () => { await ui.host("setSetting", { key: "mcpp.build.target", value: row.host ? "" : row.target }); render(); }, { secondary: true }); + const toolchains = row.toolchains.length + ? row.toolchains.map((tc) => h("div", tc.spec || "—", " ", ui.badge(tc.status === "installed" ? "ok" : "info", tc.status), tc.default ? ` ${t("(default)")}` : "")) + : h("span.muted", "—"); + const install = !row.installed && row.pin + ? ui.button(t("Install"), () => ui.rpc("toolchains/install", { spec: row.pin, target: row.target, root: rootDir }), { secondary: true }) + : null; + return h(`tr${row.selected ? ".selected" : ""}`, + h("td", h("strong", row.target), row.host ? h("span.muted", ` ${t("(this machine)")}`) : null, row.note ? h("div.muted", row.note) : null), + h("td", toolchains, install), + h("td", details), + h("td", choose)); + }); + el.appendChild(h("table.targets", + h("thead", h("tr", h("th", t("Target")), h("th", t("Toolchains")), h("th", t("Platform")), h("th", ""))), + h("tbody", rows))); + } + const offs = [ + ui.on("job/finished", (p) => { if (p.kind === "toolchain") render(); }), + ui.on("job/plan", (p) => { if (p.root === rootDir) render(); }), + ]; + render(); + return () => offs.forEach((off) => off()); + }, + }; +})(typeof window !== "undefined" ? window : globalThis); diff --git a/webui/js/types.d.ts b/webui/js/types.d.ts new file mode 100644 index 0000000..1c1d8e4 --- /dev/null +++ b/webui/js/types.d.ts @@ -0,0 +1,43 @@ +// The panels' one global, for `tsc --checkJs` (vscode: npm run check:webui). Not loaded at run time. +interface McppPanel { + title(params: any): string; + mount(el: HTMLElement, params: any): void | (() => void); +} + +interface McppUiApi { + panels: Record; + setBundle(b: Record): void; + t(key: string, ...args: unknown[]): string; + formatBytes(bytes: number): string; + ago(when: number | null | undefined, now?: number): string; + debounce(fn: (...args: any[]) => void, ms: number): (...args: any[]) => void; + h(spec: string, props?: any, ...children: any[]): any; + clear(el: E): E; + badge(state: string, text: string): HTMLElement; + button(text: string, onclick: (ev?: Event) => unknown, opts?: { secondary?: boolean; disabled?: boolean; title?: string }): HTMLButtonElement; + section(title: string, ...children: any[]): HTMLElement; + empty(text: string): HTMLElement; + errorBox(error: any): HTMLElement; + rpc(method: string, params?: unknown): Promise; + host(action: string, params?: unknown): Promise; + on(method: string, fn: (...args: any[]) => void): () => void; + ready(): void; + state: { get(): any; set(s: any): void }; + editor: "vscode" | "jetbrains"; + graphLayout: { + layout(nodes: any[], edges: any[], opts?: any): { nodes: any[]; edges: any[]; width: number; height: number }; + neighbourhood(nodes: any[], edges: any[], focus: string, depth?: number): { nodes: any[]; edges: any[] }; + }; + cleanup(action: string, root?: string): Promise; +} + +interface Window { + McppUi: McppUiApi; + acquireVsCodeApi?: () => { postMessage(m: unknown): void; getState(): any; setState(s: any): void }; + mcppHostSend?: (text: string) => void; + mcppHostReceive: (m: unknown) => void; + mcppHostAttached: () => void; + __mcppState: any; +} + +declare var McppUi: McppUiApi; diff --git a/webui/styles.css b/webui/styles.css new file mode 100644 index 0000000..7e4f110 --- /dev/null +++ b/webui/styles.css @@ -0,0 +1,71 @@ +/* The panels' look. Colours come from the editor: VS Code's theme variables, or the --mcpp-* ones + the JetBrains host sets from its own theme in `init`; the fallbacks are a neutral dark theme. */ +:root { + --fg: var(--mcpp-fg, var(--vscode-foreground, #cccccc)); + --bg: var(--mcpp-bg, var(--vscode-editor-background, #1e1e1e)); + --muted: var(--mcpp-muted, var(--vscode-descriptionForeground, #9d9d9d)); + --border: var(--mcpp-border, var(--vscode-panel-border, #3c3c3c)); + --card: var(--mcpp-card, var(--vscode-sideBar-background, #252526)); + --accent: var(--mcpp-accent, var(--vscode-button-background, #0e639c)); + --accent-fg: var(--mcpp-accent-fg, var(--vscode-button-foreground, #ffffff)); + --secondary: var(--mcpp-secondary, var(--vscode-button-secondaryBackground, #3a3d41)); + --secondary-fg: var(--mcpp-secondary-fg, var(--vscode-button-secondaryForeground, #ffffff)); + --input: var(--mcpp-input, var(--vscode-input-background, #3c3c3c)); + --ok: var(--mcpp-ok, #89d185); + --warn: var(--mcpp-warn, #e2c08d); + --err: var(--mcpp-err, var(--vscode-errorForeground, #f48771)); + --font: var(--mcpp-font, var(--vscode-font-family, system-ui, sans-serif)); + --mono: var(--mcpp-mono, var(--vscode-editor-font-family, ui-monospace, monospace)); + --size: var(--mcpp-font-size, var(--vscode-font-size, 13px)); +} +* { box-sizing: border-box; } +body { margin: 0; padding: 12px 16px; color: var(--fg); background: var(--bg); font: var(--size)/1.45 var(--font); } +h1 { font-size: 1.4em; margin: 0 0 4px; } +h2 { font-size: 1.05em; margin: 0 0 8px; } +code, pre { font-family: var(--mono); } +a { color: var(--accent); } +.muted, .empty { color: var(--muted); } +.panel-head { margin-bottom: 12px; } +.card { background: var(--card); border: 1px solid var(--border); border-radius: 6px; padding: 10px 12px; margin: 10px 0; } +.actions, .toolbar { display: flex; gap: 6px; align-items: center; flex-wrap: wrap; margin-top: 8px; } +button { background: var(--accent); color: var(--accent-fg); border: 0; border-radius: 3px; padding: 4px 10px; font: inherit; cursor: pointer; } +button.secondary { background: var(--secondary); color: var(--secondary-fg); } +button:disabled { opacity: .5; cursor: default; } +input, select, textarea { background: var(--input); color: var(--fg); border: 1px solid var(--border); border-radius: 3px; padding: 3px 6px; font: inherit; } +input[type="search"] { min-width: 220px; } +textarea { width: 100%; font-family: var(--mono); } +.badge { display: inline-block; padding: 0 6px; border-radius: 8px; font-size: .85em; border: 1px solid currentColor; } +.badge-ok { color: var(--ok); } .badge-warning { color: var(--warn); } .badge-error { color: var(--err); } .badge-info, .badge-running { color: var(--muted); } +.error { color: var(--err); } +.error pre { white-space: pre-wrap; color: var(--fg); } +.note { color: var(--warn); } +dl.facts { display: grid; grid-template-columns: max-content 1fr; gap: 4px 12px; margin: 0; } +dl.facts dt { color: var(--muted); } +dl.facts dd { margin: 0; } +ul.list { list-style: none; padding: 0; margin: 0; } +ul.list li { display: flex; justify-content: space-between; gap: 8px; padding: 3px 0; border-bottom: 1px solid var(--border); } +ul.list li:last-child { border-bottom: 0; } +li.package { display: block !important; cursor: pointer; } +li.package:hover { background: var(--card); } +table { border-collapse: collapse; width: 100%; } +td, th { padding: 4px 6px; text-align: left; vertical-align: top; border-bottom: 1px solid var(--border); } +table.targets tr.selected { background: var(--card); } +table.bars td.num { text-align: right; white-space: nowrap; width: 7em; } +table.bars td.bar { width: 40%; } +table.bars td.bar div { height: 8px; background: var(--accent); border-radius: 2px; } +table.fields td { border: 0; padding: 1px 6px; } +.setting { padding: 6px 0; border-bottom: 1px solid var(--border); } +.setting:last-child { border-bottom: 0; } +.setting p { margin: 2px 0 4px; } +.graph-canvas { position: relative; height: calc(100vh - 150px); min-height: 320px; border: 1px solid var(--border); border-radius: 6px; overflow: hidden; } +.graph-canvas svg { display: block; } +.node rect { fill: var(--card); stroke: var(--border); } +.node.focus rect { stroke: var(--accent); stroke-width: 2; } +.node.kind-external rect { stroke-dasharray: 4 3; } +.node text { fill: var(--fg); font-size: 12px; font-family: var(--mono); pointer-events: none; } +.node { cursor: pointer; } +.edge { fill: none; stroke: var(--muted); stroke-width: 1; } +.edge.back { stroke: var(--warn); stroke-dasharray: 4 3; } +.arrow { fill: var(--muted); } +pre.log { max-height: 40vh; overflow: auto; background: var(--card); padding: 8px; border-radius: 4px; white-space: pre-wrap; } +details summary { cursor: pointer; } diff --git a/webui/tests/layout.test.js b/webui/tests/layout.test.js new file mode 100644 index 0000000..ac6ac93 --- /dev/null +++ b/webui/tests/layout.test.js @@ -0,0 +1,41 @@ +// The layered layout and the neighbourhood: every edge that is not part of a cycle points down a +// layer, nodes of a layer do not overlap, and a neighbourhood holds exactly the nodes in reach. +const assert = require("node:assert/strict"); +const { test } = require("node:test"); +const { load } = require("./load"); + +const ui = load(["js/core.js", "js/graph-layout.js"]); + +test("edges point from a layer to a lower one; cycles are drawn, not obeyed", () => { + const nodes = ["app", "lib", "std", "a", "b"].map((id) => ({ id })); + const edges = [{ from: "app", to: "lib" }, { from: "lib", to: "std" }, { from: "app", to: "std" }, { from: "a", to: "b" }, { from: "b", to: "a" }]; + const l = ui.graphLayout.layout(nodes, edges); + const at = new Map(l.nodes.map((n) => [n.id, n])); + for (const e of l.edges) if (!e.back) assert.ok(at.get(e.from).layer < at.get(e.to).layer, `${e.from} -> ${e.to}`); + assert.equal(l.edges.filter((e) => e.back).length, 1); + const byLayer = new Map(); + for (const n of l.nodes) { + const row = byLayer.get(n.layer) || []; + for (const m of row) assert.ok(Math.abs(m.x - n.x) >= n.width, "overlap"); + row.push(n); + byLayer.set(n.layer, row); + } + assert.ok(l.width > 0 && l.height > 0); +}); + +test("a neighbourhood is the nodes within reach, both ways", () => { + const nodes = ["a", "b", "c", "d"].map((id) => ({ id })); + const edges = [{ from: "a", to: "b" }, { from: "b", to: "c" }, { from: "c", to: "d" }]; + const one = ui.graphLayout.neighbourhood(nodes, edges, "b", 1); + assert.deepEqual(one.nodes.map((n) => n.id).sort(), ["a", "b", "c"]); + const two = ui.graphLayout.neighbourhood(nodes, edges, "b", 2); + assert.equal(two.nodes.length, 4); +}); + +test("strings and sizes", () => { + ui.setBundle({ "{0} packages": "{0} 个包" }); + assert.equal(ui.t("{0} packages", 3), "3 个包"); + assert.equal(ui.t("missing {0}", "x"), "missing x"); + assert.equal(ui.formatBytes(1536), "1.5 KiB"); + assert.equal(ui.formatBytes(10), "10 B"); +}); diff --git a/webui/tests/load.js b/webui/tests/load.js new file mode 100644 index 0000000..f4d379d --- /dev/null +++ b/webui/tests/load.js @@ -0,0 +1,16 @@ +// Loads the panels' classic scripts into a context: Node's own global for the pure ones, a jsdom +// window for the ones that render. +const fs = require("node:fs"); +const path = require("node:path"); +const vm = require("node:vm"); + +const webui = path.resolve(__dirname, ".."); + +function load(files, context) { + const g = context || { console, setTimeout, clearTimeout }; + if (!context) { g.globalThis = g; vm.createContext(g); } + for (const f of files) vm.runInContext(fs.readFileSync(path.join(webui, f), "utf8"), g, { filename: f }); + return g.McppUi; +} + +module.exports = { load, webui }; diff --git a/webui/tests/panels.test.js b/webui/tests/panels.test.js new file mode 100644 index 0000000..390ee1a --- /dev/null +++ b/webui/tests/panels.test.js @@ -0,0 +1,118 @@ +// Every panel, mounted in a DOM against the real backend over the mock mcpp: the host is played the +// way the JetBrains plugin plays it (window.mcppHostSend out, window.mcppHostReceive in), and each +// panel must render what the golden fixtures hold without an error box. +const assert = require("node:assert/strict"); +const fs = require("node:fs"); +const os = require("node:os"); +const path = require("node:path"); +const { test, before, after } = require("node:test"); + +const repo = path.resolve(__dirname, "..", ".."); +const vscodeDir = path.join(repo, "vscode"); +const { JSDOM } = require(path.join(vscodeDir, "node_modules", "jsdom")); +const { Backend } = require(path.join(vscodeDir, "out", "src", "backend", "client.js")); +const { built } = require(path.join(vscodeDir, "out", "test", "unit", "harness.js")); + +const scripts = ["core.js", "host.js", "graph-layout.js", "panels/project.js", "panels/libraries.js", "panels/cache.js", + "panels/settings.js", "panels/graph.js", "panels/pack.js", "panels/targets.js", "app.js"].map((f) => path.join(repo, "webui", "js", f)); + +let backend, root, skip; +const hostCalls = []; + +before(async () => { + const program = built("mcpp-ide"), mock = built("mcpp-ide-mock-mcpp"); + if (!program || !mock) { skip = "build the backend first (mcpp build)"; return; } + root = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-webui-")); + fs.mkdirSync(path.join(root, "src")); + fs.writeFileSync(path.join(root, "mcpp.toml"), '[package]\nname = "app"\nversion = "0.1.0"\n'); + backend = new Backend({ program }); + await backend.request("initialize", { editor: "jetbrains", settings: { "mcpp.path": mock }, workspaceFolders: [root] }); +}); + +after(async () => { if (backend) await backend.stop(); }); + +function mount(panel, params) { + const dom = new JSDOM('
', { runScripts: "outside-only", pretendToBeVisual: true }); + const w = dom.window; + w.mcppHostSend = async (text) => { + const m = JSON.parse(text); + if (m.type === "ready") { w.mcppHostReceive({ type: "init", panel, params, bundle: {} }); return; } + if (m.type === "rpc") { + try { w.mcppHostReceive({ type: "rpcResult", id: m.id, result: await backend.request(m.method, m.params) }); } + catch (e) { w.mcppHostReceive({ type: "rpcError", id: m.id, error: { message: e.message } }); } + return; + } + if (m.type === "host") { + hostCalls.push(m.action); + const answers = { settings: {}, setSetting: true, confirm: { confirmed: false } }; + w.mcppHostReceive({ type: "hostResult", id: m.id, result: answers[m.action] ?? true }); + } + }; + for (const f of scripts) w.eval(fs.readFileSync(f, "utf8")); + return w; +} + +async function settle(w, predicate, what) { + for (let i = 0; i < 200; i++) { + if (predicate(w.document)) return; + await new Promise((r) => setTimeout(r, 25)); + } + assert.fail(`${what}: ${w.document.getElementById("app").textContent.slice(0, 400)}`); +} + +const noError = (w) => assert.equal(w.document.querySelector(".error"), null, w.document.querySelector(".error")?.textContent); + +test("project", async (t) => { + if (skip) return t.skip(skip); + const w = mount("project", { root }); + await settle(w, (d) => d.body.textContent.includes("Tests (1)"), "the project's test"); + assert.ok(w.document.body.textContent.includes("app")); + noError(w); +}); + +test("targets", async (t) => { + if (skip) return t.skip(skip); + const w = mount("targets", { root }); + await settle(w, (d) => d.querySelectorAll("table.targets tbody tr").length > 0, "target rows"); + assert.equal(w.document.querySelectorAll("tr.selected").length, 1); + noError(w); +}); + +test("libraries", async (t) => { + if (skip) return t.skip(skip); + const w = mount("libraries", { root }); + await settle(w, (d) => d.querySelectorAll("li.package").length > 0, "packages"); + w.document.querySelector("li.package").dispatchEvent(new w.MouseEvent("click", { bubbles: true })); + await settle(w, (d) => d.querySelector("select") && d.body.textContent.includes("Add to mcpp.toml"), "a package page"); + noError(w); +}); + +test("cache", async (t) => { + if (skip) return t.skip(skip); + const w = mount("cache", { root }); + await settle(w, (d) => d.querySelectorAll("table.bars tr").length > 0, "cache bars"); + noError(w); +}); + +test("settings", async (t) => { + if (skip) return t.skip(skip); + const w = mount("settings", {}); + await settle(w, (d) => d.body.textContent.includes("mcpp.path"), "the settings"); + noError(w); +}); + +test("graphs", async (t) => { + if (skip) return t.skip(skip); + for (const graph of ["packages", "modules"]) { + const w = mount("graph", { root, graph }); + await settle(w, (d) => d.querySelectorAll(".node").length > 0, `${graph} nodes`); + noError(w); + } +}); + +test("pack", async (t) => { + if (skip) return t.skip(skip); + const w = mount("pack", { root }); + await settle(w, (d) => d.querySelectorAll("select option").length > 2, "pack formats"); + noError(w); +}); diff --git a/webui/tsconfig.json b/webui/tsconfig.json new file mode 100644 index 0000000..0ab6899 --- /dev/null +++ b/webui/tsconfig.json @@ -0,0 +1,14 @@ +{ + "compilerOptions": { + "allowJs": true, + "checkJs": true, + "noEmit": true, + "target": "ES2022", + "lib": ["ES2022", "DOM"], + "strict": false, + "noImplicitAny": false, + "skipLibCheck": true, + "types": [] + }, + "include": ["js/**/*.js", "js/types.d.ts"] +} From 43123c4c68f554b3dd077ffe1d3a2a28fc6cf03b Mon Sep 17 00:00:00 2001 From: Sunrisepeak Date: Wed, 28 Oct 2026 02:42:22 +0900 Subject: [PATCH 04/30] vscode: mcpp-vscode 1.0.0 as the adapter of mcpp-ide The extension starts the backend (bundled bin//, mcpp.ide.backendPath, xlings or PATH) and maps its protocol onto VS Code: build and test tasks in a pseudoterminal showing mcpp's narration (closing it cancels), the Testing view from mcpp test --list, debug configurations of type mcpp for CodeLLDB, cppdbg, lldb-dap or Native Debug, Problems from mcpp's located diagnostics and mcpp.toml's from mcpp, the project tree, the status bar, the shared panels, and mcpp.toml editing help from the backend. Every command id of 0.9 is kept; package.json's commands, keybindings, menus and configuration are generated from spec/ (mcpp-ide-dev gen vscode --stage). mcppls is an extension pack, not a dependency; no language service is registered. Tests: unit (the wire against the real backend, the mappings, the locators) and an extension-host suite in VS Code 1.91 over the mock mcpp. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- src/bin/dev.cpp | 10 +- vscode/.vscodeignore | 2 + vscode/CHANGELOG.md | 18 + vscode/README.md | 56 + vscode/media/activity-bar.png | Bin 0 -> 2426 bytes vscode/media/logo.png | Bin 0 -> 31749 bytes vscode/package-lock.json | 4852 ++++++++++++++++++ vscode/package.json | 301 ++ vscode/src/backend/client.ts | 164 + vscode/src/backend/locate.ts | 65 + vscode/src/backend/mcppls.ts | 18 + vscode/src/commands.ts | 211 + vscode/src/debug.ts | 66 + vscode/src/diagnostics.ts | 88 + vscode/src/extension.ts | 84 + vscode/src/jobs.ts | 105 + vscode/src/mapping.ts | 56 + vscode/src/panels.ts | 165 + vscode/src/projectTree.ts | 117 + vscode/src/projects.ts | 69 + vscode/src/protocol.ts | 150 + vscode/src/run.ts | 27 + vscode/src/session.ts | 177 + vscode/src/status.ts | 49 + vscode/src/tasks.ts | 115 + vscode/src/testing.ts | 94 + vscode/src/toml.ts | 81 + vscode/syntaxes/mcpp-modules.tmLanguage.json | 72 + vscode/syntaxes/mcpp-toml.tmLanguage.json | 116 + vscode/test/e2e/runTest.ts | 46 + vscode/test/e2e/suite/index.ts | 83 + vscode/test/unit/client.test.ts | 38 + vscode/test/unit/harness.ts | 36 + vscode/test/unit/locate.test.ts | 35 + vscode/test/unit/mapping.test.ts | 27 + vscode/tsconfig.json | 17 + 36 files changed, 7608 insertions(+), 2 deletions(-) create mode 100644 vscode/.vscodeignore create mode 100644 vscode/CHANGELOG.md create mode 100644 vscode/README.md create mode 100644 vscode/media/activity-bar.png create mode 100644 vscode/media/logo.png create mode 100644 vscode/package-lock.json create mode 100644 vscode/package.json create mode 100644 vscode/src/backend/client.ts create mode 100644 vscode/src/backend/locate.ts create mode 100644 vscode/src/backend/mcppls.ts create mode 100644 vscode/src/commands.ts create mode 100644 vscode/src/debug.ts create mode 100644 vscode/src/diagnostics.ts create mode 100644 vscode/src/extension.ts create mode 100644 vscode/src/jobs.ts create mode 100644 vscode/src/mapping.ts create mode 100644 vscode/src/panels.ts create mode 100644 vscode/src/projectTree.ts create mode 100644 vscode/src/projects.ts create mode 100644 vscode/src/protocol.ts create mode 100644 vscode/src/run.ts create mode 100644 vscode/src/session.ts create mode 100644 vscode/src/status.ts create mode 100644 vscode/src/tasks.ts create mode 100644 vscode/src/testing.ts create mode 100644 vscode/src/toml.ts create mode 100644 vscode/syntaxes/mcpp-modules.tmLanguage.json create mode 100644 vscode/syntaxes/mcpp-toml.tmLanguage.json create mode 100644 vscode/test/e2e/runTest.ts create mode 100644 vscode/test/e2e/suite/index.ts create mode 100644 vscode/test/unit/client.test.ts create mode 100644 vscode/test/unit/harness.ts create mode 100644 vscode/test/unit/locate.test.ts create mode 100644 vscode/test/unit/mapping.test.ts create mode 100644 vscode/tsconfig.json diff --git a/src/bin/dev.cpp b/src/bin/dev.cpp index a6a3170..05d4d9c 100644 --- a/src/bin/dev.cpp +++ b/src/bin/dev.cpp @@ -281,12 +281,18 @@ int gen_vscode(std::span args) { copy_tree(root / "vscode" / "out" / "src", out / "out" / "src"); copy_tree(root / "vscode" / "media", out / "media"); copy_tree(root / "vscode" / "syntaxes", out / "syntaxes"); - static constexpr std::array webuiSkip{"tests", "tsconfig.json"}; + static constexpr std::array webuiSkip{"tests", "tsconfig.json", "js/types.d.ts"}; copy_tree(root / "webui", out / "webui", webuiSkip); for (const auto* f : {"README.md", "CHANGELOG.md", ".vscodeignore"}) if (fs::exists(root / "vscode" / f)) fs::copy_file(root / "vscode" / f, out / f, fs::copy_options::overwrite_existing); fs::copy_file(root / "LICENSE", out / "LICENSE.txt", fs::copy_options::overwrite_existing); - if (auto backends = option(args, "--backends")) copy_tree(*backends, out / "bin"); + // The runtime strings, for what the extension says before its backend runs. + fs::create_directories(out / "i18n"); + fs::copy_file(root / "spec" / "i18n" / "runtime.zh-cn.json", out / "i18n" / "runtime.zh-cn.json", fs::copy_options::overwrite_existing); + // The backend programs, laid out bin//mcpp-ide[.exe]: --backends, else MCPP_IDE_BACKENDS. + auto backends = option(args, "--backends"); + if (!backends) backends = mcpplibs::os::env::get("MCPP_IDE_BACKENDS"); + if (backends && !backends->empty()) copy_tree(*backends, out / "bin"); } std::println("vscode declarations in {}", out.generic_string()); return 0; diff --git a/vscode/.vscodeignore b/vscode/.vscodeignore new file mode 100644 index 0000000..40fbe32 --- /dev/null +++ b/vscode/.vscodeignore @@ -0,0 +1,2 @@ +**/*.map +out/test/** diff --git a/vscode/CHANGELOG.md b/vscode/CHANGELOG.md new file mode 100644 index 0000000..0ad0958 --- /dev/null +++ b/vscode/CHANGELOG.md @@ -0,0 +1,18 @@ +# Changelog + +## 1.0.0 + +- The extension is the VS Code adapter of mcpp-ide: its decisions are the mcpp-ide backend's + (`mcpp-ide serve`, shipped inside the extension), which reads mcpp's control contract. The same + features exist in CLion through mcpp-clion. +- Builds and tests run as tasks in a pseudoterminal that shows mcpp's own narration; closing the + terminal cancels the build. Problems come from mcpp's located diagnostics, not from a pattern. +- The Testing view lists every test of every project (`mcpp test --list`) and runs one or all. +- Debugging through a launch configuration of type `mcpp`, for CodeLLDB, the C/C++ extension, + lldb-dap or Native Debug; an ok image is debugged through `okrun`. +- Targets and platforms: the targets mcpp knows, their toolchains and the platform that configures + each; `mcpp.build.target` chooses the target build, run, test, debug and pack use. +- mcpp.toml's problems come from mcpp; the extension's own TOML checks are removed and their + settings deprecated. +- mcppls is installed with the extension as an extension pack rather than required; the project + view reports whether the installed mcppls reads mcpp's result record (0.0.18 and later). diff --git a/vscode/README.md b/vscode/README.md new file mode 100644 index 0000000..b56ff20 --- /dev/null +++ b/vscode/README.md @@ -0,0 +1,56 @@ +# mcpp for Visual Studio Code + +**English** | [简体中文](https://github.com/mcpp-community/mcpp-ide/blob/main/README.zh-CN.md) + +Build, run, test, debug and pack [mcpp](https://github.com/mcpp-community/mcpp) C++23 module +projects, browse their libraries, dependency and module graphs, targets and platforms, and manage +mcpp's shared build cache. + +This extension is the VS Code adapter of [mcpp-ide](https://github.com/mcpp-community/mcpp-ide). +Its decisions are made by the mcpp-ide backend (`mcpp-ide serve`), which reads only mcpp's +machine contract; JetBrains CLion has the same features through mcpp-clion. + +## Language features come from mcppls + +Completion, navigation, highlighting and diagnostics of C++ files come from the +[C++ Modules language server](https://marketplace.visualstudio.com/items?itemName=sunrisepeak.mcpp-language-server) +(mcppls), which this extension installs with it (an extension pack: it can be uninstalled +separately). This extension registers no language service. mcppls 0.0.18 and later refresh after +every build, whoever runs it; the project view says when the installed mcppls is older or missing. + +## Features + +| Feature | Where | +|---|---| +| Build and test | Tasks of type `mcpp` in a terminal that shows mcpp's own output, in colour; closing it cancels the build | +| Run | The program in a terminal of its own, started the way `mcpp run` starts it | +| Debug | A launch configuration of type `mcpp`; the debugger is CodeLLDB, the C/C++ extension, lldb-dap or Native Debug. An ok image (`--target -openkal`) is debugged through `okrun` | +| Tests | The Testing view: every test of every project, run one or all | +| Problems | mcpp's diagnostics, located where mcpp reports them; mcpp.toml's problems from mcpp itself | +| Targets and platforms | The targets mcpp knows, their toolchains and the platform that configures each; the build target is chosen in the status bar | +| Libraries | The packages of mcpp's indexes; `mcpp add` from a package's page | +| Graphs | The package dependency graph and the module graph of a project | +| Cache | The shared build cache by kind, package and age; cleanups with a preview and a confirmation at their level of danger | +| Pack | The formats a project can be packed into, and the result | +| mcpp.toml | Completion, hover and outline from mcpp's own key registry | + +## Requirements + +- mcpp 2026.10.26.1 or later (`xlings install mcpp`). +- The mcpp-ide backend: shipped inside the extension for Linux, macOS and Windows; otherwise + `xlings install mcpp-ide`, or set `mcpp.ide.backendPath`. + +## Upgrading from 0.9 + +The extension ID is unchanged (`mcpp-community.mcpp-vscode`), and so are its command IDs and +setting keys. Settings that described the removed TOML checks are kept and marked deprecated; the +problems of mcpp.toml now come from mcpp. + +## Untrusted workspaces + +In an untrusted workspace mcpp runs with the effects listed in `mcpp.trust.denyEffects` denied +(`mcpp --deny`): a command that needs one of them stops before it and says so. + +## License + +Apache-2.0 diff --git a/vscode/media/activity-bar.png b/vscode/media/activity-bar.png new file mode 100644 index 0000000000000000000000000000000000000000..4cec8e65d255552d28058723d9e2a1be177f4d06 GIT binary patch literal 2426 zcmV-=35E8FP)1i$6z08_QlKb70TBch(5e+dkVOnG&=wWJg1A6c+#n`It0=CZh>B4ZK|_E*T)_p! z4F&fQRMg^zqNr7iC~GMcwS{hPi97Xs_00#g(1K{w+20*6uAaelh0KFc3gA;9MDec(oD7 zaf2cau<`8x6ash?K&fTjWdJGw>;+KHfA6q9Q^Mz|!GEI~z^x&kt3d(i3*Zm@f7Aom z0AN6X4O9;`8o-|f@^=6q0yq~ydYm3s8Oun^I93Dr3*pB5Jn@YNfU5!2Y8G102kl@u zPZt26Y35OYOyuc^Wu0AkQp*wBP{!7$F#+(X$6~9j2fohm$espZyD-mAo{q3C=OpVi zu5!4NScaP8P6p?s1CUNX>NVCIvWGlwv^1Ur&@#m458}zHL;S`j8cZbF0JOE(!#bbE zmNBsU%{AJ`J$w(KW5D(G1Mmgiq1RB~`?(d*-mqBD3IIR)+@t>QBeJBV0&s-Ik-znM zI7QzsHJIy4pTJl~N@%*aYycnoY~&UzFh4*VdMGVgT_^CwRr|Q2hvE>MVgle;QZ>JE zmq8qu!k8fq1S0`~eV*%Q06mfkz^NJvsvED80($xCSw0(f zfQ-vzT`Gy%>M_?(016DO_Y}r3Y3%2kBFO?^JQEndp*VeSk9ky(e%EJ?YRUnAYwBvT zo>v6dquj=8%-W-dL0o~k*<)QQZe%43fIAG?MIGs=G*7+(kTpJY*sN@}uqFk_ivjWy zXY%%uk8x!u3xG!gP`9N5caAa;)*1j%|k7o zHCt`T3|XS0;}Z>lavcw9EKXU&g_I0*etoM$NmRadra|y^#+IqVTIOqnHnp}VLg+`* z^G*`n(6$)jOK1QN7I?ej%O^9zSs+-k9k5hUNPt!87sX6^Vr%_i?>puI{HUqDyW+?7Mj z5-95}aVQ;T(uGAdU}SpK1X?igM;iiwBLxN2&GV!5*)^KYDHYtzMoI~Nh2qRAGAH{x z+OtIH9u=|rWdMg*r+FR=@ka$T(3{8x&uRz&F4r7+Wyy<(yz{fY48=Oz_s^z|6&Hs~7Hq4F@fS#PYG9Z{L{=Lq1+#PQK+6Wae1<1t$eOqc!5K&{d!(x;bEfW|= z50~_?TTnZXjuC(pcv7nZ0^pP`;ts%BLf}*tr0yR1!ruk}6uU~7b2Py1bQQ#NHGv+? z#A6MPeffPs0cge3TTihvZUD3(wbW&s3p})S)s66t0RT_AlC;}2no>EFE~i0M2(GGo zi28PGUTv7qRFMo!CI|!Ac$Vb~$ac`pqU^qj>v)OfSXDRa&r{hvEC4w?k~+S9p2vOa z3m@~5tyKbdql-0MBQUK|E;_tf=%P3=z~<+W9>2wGeGS`T>Ur&DR=thi_bkam8vB+O z^S<|}h1EEUNM(+Dm1`Uu27m~a$ZCOacQ&X{c?IKA@_FYyBQ;EEKS_Z7nQlTaQDwk3 zmg^1Ul+zF{qq|ui;69tI1O}k3pnTTTSEm^;gL?#SZwq*BH090;4O1#|&AUWkR11B| zpzfBKtpvD=fxUvyr{?;AiP!Tiug)bINTaL#oA=tSjkONau$=C7Iqy9`C;$;28=bhe zFF-LubsaqJ3gZ8;b780^+36@y(M7I!Qy^r*>eyeP^SOe73}Tj>OV>7*Zm7y3=tVeR z)Fp-FQh*%5dF)o57aU4#l=nu00+8boL_Y|a?yJRIL>*}vRm9F7MeSQP-?_oXmRd7G zs}tH9Cxq-RJ&_7)7#eCPhp(H|i~TliiAMmP79!oZ+rmv$%3+#bp>qD+`MKeO9Budh z6ohCc>`zxz6;RU7a-4u-hc*@%fHX?5QnOTLfIgkDS67Yfp^V{X*Qv2%OtnXlFVtk} zekY)mzI{Z%Q*Mii8!4BB0wCX~9b>J@@Cct*0E0V@8s+Xp3xilw}nr^`I zbp5C^c{0<(0MLb;)~h--H9>E(%oOU*y1vXle4E89-*}%)B+GC!!z!xLSmfx*K85lU zW`v0VV63JRb$~8K_xUq<^u5Mj_6Ut?46jq^{^;dT>q#fm6STl%Y4Pr{P_VKHH+H*0 zVpPsfxyh{LwRXf7n{sCGjhLe;gA_6bO(RR2$nVPu`_6#wkJosd0F@7%oj?m|DRfR0 zd$g;!peDaFK*9ePQsYbbR^%l5|M`q9UlG(=fslL`wgf6ku^T{TFeYMUmB}s zgQ@m^$Pjo s!~z!Q(^3GWt`q<%08&>9fTni+3)&=8YG~wN3;+NC07*qoM6N<$f?xY-6951J literal 0 HcmV?d00001 diff --git a/vscode/media/logo.png b/vscode/media/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..a9c8f84cfb9425a7e0a38a60b24f8f5b50669be5 GIT binary patch literal 31749 zcmeEt1yfwx67CEP?mjrdA-KD{Yw+M9xVsGyAZXCw5L^NY!JPquySs(p?hbFxJ@>x< z@Ty*|nwqLTd-m$ptGieC*WZrPP?N_%B|!xM02qo2GFkutF!rAhG9v8CpkS&J>fodn`qWqXK)=P$T!pi78Q zYv)6>6+F@Hk-zKQsx2!~r2&@ye}~m3P>=BEFZN#))&Ct31ayDA|NHYc5Dje5JlHYd z2mN=zMYJPT{&&<|KoDXpSFB8}M9uykz@9bux&ICWUnrd1JEt1&|h z6~ICi@S}u&B8bfAR9zJM>sb52a@yqRSC9yf;6(Sb+ccNBqCQLQjlj zh&fG6=#TG#wbu~XkkAw{W0~SW05^QlOgVJGvin!``)u2+;_-Q`iJ1RR){zw(A{&!{rQEUJ<`5rop8T#KhkFWpgq+%Uj z8c>H(r-BBC_Z@f%{&$fFw=j1*=bXu<+sMFO&TL2nNA{-Olkx z&L8{#PyYYa{{OVWX{b`T0G;@aDa4Im44YQo1DJ~b;1m_)D9~+5Fzc$Kc}*FzmVbbgJgQKPE5W6ysO)jkYzTF^ znEkc;0p_`9L0CSKY7)~92~otoN!(BnxW4%XCIn#CZ3C?g_l+tnzAVLsYrwl|YO zy)BcmNGxXQ=QJB$!1q`iw*Vmf#wCEl`{BJBFbY3G1@4?SLE&}mDI>V?gXo3;R+Ffq z&Q8h5QphlC=cd~}))oKjp)FGp+W5uyMrx0We(}rGCq?R1B`zyK(t|f=P&_~2^o*&@ z^cn$FQhBm$Ql0|WH#qv)L?m`$drP6W5P%o#a61vm;Q zK2}cZVPh}RNEm^dCQ(+9f%8HT`zLpXi9!G7-P`_|sKqUPtiSs}?@^7W!_1AFd0Y9U zpK`%%z^1k!=$5X8BD^9ZpGVJbUmhY5F2aM&S|WcrZ+jg~PFp|CM403!lhnD*z;f#8 z8*mn%j`*4`2uHZKsr_g|P#7(3@ng~J^Dh@_Q>SyXVWAV(mA%mYGS-)laL%Lb}%={MPvJbJ5>R3j56e$9a+skC4C zx*U4Kj0Q$%#)2kLak$e~2jEr*eU&4^kfho}cyhprl*2j)VJibBLD*4;>Wru>$nd2< z;g*dc(nOG*VF~%ViQ1aeMv8$|_*iPN?%Dn-za3$lYVrm-pC+Gu6S1n#)IL*51=l{) zj>+^dgkVo~NzYN~tFO5S6k2#zcekGakwx*i=gSE89jn`L!bQd*eoP+2g4gzb0Z}|o z*^>QhHaNCH^3)kWc=S%#NRCdcA&IBt&{M=t?k&;~q+P)6C}2(vUXIr)SVj&vAMA2N zUtLSE5Qw4a1Cd=*m0KI3S9)F&`qqea1AQub4R$;_==w2^OJ_aHf<)Y zzU`l^lf4m##h65PgcL2{*l8n|SVFssu&tI?OyE3(fedM>8(MA;?Wl#8Btwn*dBSyB zNq1H_C3bB7Xv7sP6}C8)96E*9HT2Ao*$Y>mS2svY)W4&}@(Iw&J44R`yr%mmotS%c zG4>FYB?}=iRJ>hEr;hO~aDP=srVK_qKeS0as=FlieXorM_7zfV$(Q2?yrq9@R+(9e z)1UK9y%-F~uPjGoqz+FS50GaEmi}P=sKdM{8K+JY{b&Qc9Rqxboq50vfm~-zB2UgrAH;j-ZFWTe%v{2h5G& zG@STBZ7G8z_6rAR%qDyJ%Uv9|Ze2?fTQ8hk$H|XNc(i`tVF`SmenFz#8?&xUDh>`h z_Xm>dSCO;tVbGYz5Eqq0s??7lT|Q8N7sA<{1q9H&ggHNbojfD1jLLi|ylT+5x0SQ? zFdcv(;9iK^zLDVW)x3#0)3eHf`|=BIgH#l$17{i*UxC$Z(9hk+%8esJf3q>N<(P4# zkGdsg#!n>g?u216#A2f?>;jvRpt1g&>(bmI^^*K-1pLt%<6`BwH&tSpMgkY@JM4o|1r47aof?z z9P3%F^}%j}`_507XrSnpO_%vEAf$EL0!eScc!4a>Q#q%}45zf!yJXe(ptCF*Xhh*o zylFHIr!~CZXsaWyVaXvZzVh5;0v zAJEYq=5-YQfOc{6Zev1r!~fwGyT?jJyg>*)1QRgG?uN z2ckm|ndb_=R+Ip4<5;2PvO11akRIx$imt)%AS?lObJKh1Rr#)B3->Zi1C=MTQ_F=9 z=;aVI7q3OSyT{xZkYx?k3*|)UT^gH;f)=>$jHTOFB)sLNn`_o>o5>v0-NrkP^!p8fu=xg6_vNSToSX$(w&Q`+o87n@M{%(O~=kZlQ zLnGX>8vL@FEoZhF*8&X&F#3(<1}QImhh}ZD>fAC9F`MbP3nMGEX3oX#HDB_4n$9_= z^0%X3Uqrlv4WR?GHnFq=MD-uroIVF6u{HckO<9$Ced0SyK3)nP8e?K0G5Sav2DQqC8#*QdEPA?K=QOj)Gcl+2$%eIeaDaa zXixY2#Ht8ma(WrZc5@t))+zUUv}dXd4ouCSd@;?J{rfAu$;$O;Wea@;?0LDS3rKBV z3a#PkUtJ4aeG;#87{0=pnjlp_H-Y;U!r;HyI0J+YA)^c-jbGr2oDNd%zA;6hxmO~s z$;lD8Z;*>B+lofShWigNZu>AdZMK5-s;~NsNKBs&Y-PreW%oAhhghvyiC}fXK(A2% zYiaAe+Wg>24V|f-rhX*V*W_YH^H7Zr_`o?5k9@>@mIa8k01vN17FX06D7Y0GJLrp%Q9O2-Q zy$n%XK|LeD@CBCvbYM!;gnbL~uFDsd@OuehTK?}p6RR6jb>hdYtuMp1xk;4fW@Nf1 z#VOa`)Nmhgzm3KM$MS#!$(xI=bK)5ARRl%f&-US`umha8eC`<7LfBQ0yGSC0q0Q0M zp5{6=+KPBdpWg&M*J*^y7f}c485mB)<-UHLEus zPqRXHZ{TcxyuD3IjtQ+i2`sbL=- zh^^0s=gsSk#eY5?5?d!EeBmLcW%$dnz8MovHu>bgk2hv2(gL`f(fU?0z*Ihhx&VUq zL5OaFuTSw_s^{xuUw^$_*#yN%gq?{Yl&sOg`xY2zPM4*u^VNVS`e#-?o7zj(c@jw> znMywS#az0z!v82>VTYaE-=?iCvUcXroZ(n z%8B%0c;f*{LC@7SOgR{ZyQkM$|mRk7s*^4`|%ZLHo+P5Iu$HrAstb_sXXSY8* z|A`4?r*u*Kt2tobux&eR#@lzNPo`ZZ}jt7LQJ~N%%rt0%5T~vLp<{y@sf$~m>OX5dlu){~rGbbyA>Az$7_ZsB)LT^ro~Eer zce-iVlc;etkhqs6qWWWvvBl=|+SI{?UHLnmF?MFj)PF6xjE~1cx1&70vMKlMt`#3&9zBDUai)YJ2e%9E!jcIfp{B_ zXW4F%&rppf4_{mJG#8M&hC$Y$F;?6Bym;Bqte;>R)2$V*k-1w--9V0~5?qII*UHbV zGc~(~S0J&zw|G{{%ks2ED6q9JlB$FKIXnTqQ88bD*pX;Q&rS_Ol}LqVMOIEL8Kx;` zyr(Qf@ijV_S2|pAUR#`ujK?ajB%6Mh6iYb;N9c;gLQfrqpe2s$q=^|8$D1`v<28O2 zvHzGWa1x9orMbLz`2KwU&MZ&bXGURY-~pi!y`)6p`MuKCUw+|2ft9;;Q{93-rL5i! zZGpn5OhK%|4_%g1D0IANNZ`wt!3kB`<)2hR?F3O-Hi=EX@99enc+}*U>Rm>3@I}{G z@3Y^O6T`uZio1UHIi2OQMXh9})?%&CCSnnL`;MPEcxP+i6%2+FDCS|wARGU|(WH>2 z1c6|Q(U7e}p>-+#wAO2j=AvPanM1ktm29=XpsdjsWm^@|+UvVWqmb9r`JuPHe1D@k zd{J+q{BDG>o#t8v-Z1ZyOS1 z;6RRoy(&bi6+IwOLaW+8QZ>~1FM5VnX;bo^XVb9!*8xvDr|i@joxQU|Eo>XZQNuJ? zY5UiWn+1%-l2wLqsx^^$>+R$~WZjWVE*bn<0vCxF%UWM~s?nL%Ve!^YFg8?sJpj)P zC%bMp)hy#?aU=Foqj9g$g+De)q0phPPD>2)ffaz&*3LX<+Rv)=I6^}* zgdtJNn-}wG^%7*Ft$IR{xQ%Qdhswh=dohX%$Q63gf-gRtXML0OGJ(~zXK^{~yrgr2 zLxh^eS_Nr1VlNHom%VJ{?l)E1OSQF-#F)aa1(<3!R-AoAnkMuNh>|Ux^(mj!XO_S%l71`m6W`>l9%p7AUZ%(B0<-wp~}0 zxSImT@nnCT;?$W&e!ZhBGdU}>Gpr75_^m$6WkrOh*deymB8|EXLd&Q%+trRz(SZ{M z-pQ#&IvdZhce@dMz~ndevufB z_3w)3y!Xert(X!Elwl{6I$C+*DXfxqE=XGAfaNA}ormzu*>z%~?IUxO28A`gHs_{2 zU3Js*Jl%IrEpN;2@|JEH0zBTFnNk8vF!U&x#K^w(l*tWXmgk*e{ z>ZEdu77d5WceOG#ygw~txB7rK@kr^qsa!ag5?W+4RD_D!fOqoaIQxsxl+^CxZ7EyZ z6+Fi@YmQ%*kHWr90q$}w~|=(Qnll;cv|k_T`7Zgon|hEa=i zK4evjjx+!E^H8?r(GW^?AfMZTDD4s(6~WfWHg5Xta51X^Fitde8LnAI_gmefH&+b# zS+LNA=0Opl8;LuNTtwH*|L}@UYHsC@BR2yqj9@fd;WnXDV8Z_k+7dx5=O}wVi{pow z*g(b<_OB~58Z2q$pm&!@Ks*1mw=ElJyhn>Y|roICkqrIlz+qN-E z?kSnYh0}F!{N*oQQAKC@x`9h{NW)@gwYBIPSFt`yf(W#HP=LJd&@RuS26&@YZx=bG z6qj667=EWx!iZ)6IT`9L7{}UIxtl=!_t9v`mwq)QlGN#Ljh08WYG%1r)SOKzr7k9ys>PAXsJrvxc$FM;hm>MI^yp{I$7#eN_ zy=?%jFQ$y@vYpruWc@}tfmzkZ?;oork*=cCBmP7$aAi4k#=>Iun}8!$T1)dB;|~vm zQA}koY+=fz2qbfXx>MS8wN_FRh0pD$G#-EXNfI&Ci1lExbH(GY?4O7MWEl2(mYUn( z|Lw8}6GZG_DhzshM%-Aio((nAY)kJ`bQ&vjL47$q^!)Z~&a~q`X2ei1PYP-#RB;4( z^E*^~BRT2>srYU5fqO66#B`=C{-nFVwVSY?7nTLlmy+`S9PNd%>oqH#IhWhhHv(I^ z#_NU?hl0ne9a}cYl&e%Z+SFS@cO!6eeDeXb_^e)d9LQuVw8Oj!d=vL>6kE%u%=;AD zT%aTilGehAjC+mS|8W84fmkDm9YJ}xm_l91U?LQ-kq&!N<<1S2fFn7a_Nmsxmy$tQ zadKOfxVl33^-JVqe@#2^Z1rF&28R^?Wb-M)r!SphzpLEgNWvyyHtaqLYXV0oC}B@! z*)$c`_&S%H);{x`QMRUfIKK)~Wip-+yU2x8Nd~dj%m@{)-jM(cRS$`_LFjXg3b&fv z>YmMlM&D{dvNb$dxJK4=H3GG0leLeZMASdUF|Q0Ef)n{ZeR)FM#LJQ;{bZr_-zf(v zd&elXGPUt~2IU-2F;*3ByJaaB$d{2TmE}#bMiKi`N|s%r$_YU9lA;ciKI9&gdDWy}oI_TR%~BrUR{SaXU35hK)EffZJ(g6drw17HK`B#b9f=H#8e!yZ z`2M@ChrYm^9JrO6bYRVqBVXlwez@-#mKr-D2VM;LBF2Mt_Zt@ht)^ONk#SjxqS)r< zo}_b0^;v(+|SO^K-T>@skMmh1q6T(uf>oL|Sg{{u^%o8r-|)Gb7Ick+`i* zTd+ahbON=v2z3^Tu5>^Ua)@GZZY3vLF>cb$pvIk%FVQMl~~)Wq%wt`}1ECkZ0{1zXHoi8s`NhWD7t za_cSDd0*+_yd5nE>!cT=RhGO<3iXFKREGaMdx>#JwGs*vgWxCWil3J|BAV0)Pi_on zjm{rS@qxeVIFqPMQ0WYUy;-Y$+V<5Mk9@Wf(be4j<;P@3E3dh{HF=cjt=J%0#3-QV z{9ZP)DT5eh9?a8O79ac&CVS||uuGO=jt7CDDuiE`NE5yr1i#tHSbF<~j=BG_b6K%k zV}4nu1eOb-McU_-DH6oXTX}XkR@pM&ns<`S3H~1dGf)@9zp~Jcy4y}iEtF*~BeNmq znUNOCj!E}uB}+-WFLzaFQy9I(AuwQk>B7KP+SlMcl@=7qX6^06`U|J~<`2@`ZDBNj zV!>hoa&?ZAl}ECI-5UZg=ukl8KPl2OksdJEgCrAg0fd1GAcW_+$wgRmLgXU@t_j%vxEXZc-uN?vgIbVcMfcn~U8XgJ01kk= z;ft4b+41|Q(l+ie{Crhrju(A#rt13#gWONGsX)Qt{jnbgTM~ABI-9Z9%<~Oqp4~!i zAX)qsl@v-ah+H_B31{^mBX~Bs8iA~xuERg|hP5yyAr@+EUGd6(VGQCal8fn;!AOQm zo_~WUg6!S^I#;YQIgklK$Vr?pYeE}q8A{3B!QM%!XdF!;2=pxB!9z-*(n`cwd*dRA z6>ii7#$sDR74vtJPG7N6XPwwwfn8$*H@D_P`RE8_8>4_i8zRpi#rE5Sprk*SmQpy~ zpPjHX5n^B1gz{b%F|HzS%cIF&9V{%Z7^V}Il_b@cJWAYQZMm?|U4kGtCQYnAMyKgp zDX4xS2wR??&$pBz#due37`ZKpr*D8^pihn(^Y?+CgqqJfaEe2V?}Z}bkHsa6 ztRwI11z$fCay+!k744OLy`4Wne7Op8PoW~mF`HIAHXACtDgRx%5-NWhps#^) zSmW=1cQO%UiTL_Hb&1Y;2yD>i0TA#~L|Px{mBFOfzQ*yTve=<6hIIL&mp}!6>y`1& zGDEbYQ!B#MrV$1!zZ_bB>e}qp0wAI-=jLyPd$oGKM5eM2d3Z>+Tui8b%37C$6>qu_ z`%Wvib^X0j&F)+ONOc^u5;#hGIX2ToCPWa2P*GsBD6SV3YLH!f6~SL?T(;n|Sx=}X8l(lXSjM>S zes~;MjEL?=cF(|$q^%VaHQe>5Qd7A&A=*=^irQm?V3X%hHAQbCVj(PQ254P1I*(-k zQEvD^jSkm0N4bbxn3u(tcIBa~yRyKhgwTw%TXt2(w3WQ)bU*h%!P$AYCMV)+I&yJ=IL*9c=H| z9;I|w+lzR2lX+~}6++Cr)9HnR(O}?}PMH4{w&=_5JN(E}JDcxz0j~$xXE*0hdQc1T z(iW6&SmU}0?lq~X9LVUg^mj!@t#_`rm$W&}`yTjct1NYLMh(NKceBZAUcr;&ao2Cu zr)fd-Kk*Mz3&t(0m6-#S?ZLu9b}?&w-A&W*MLago7AN}d$s;qR-vSO^eK35?^X33$ zf8^_1RQeMKotLBDLN{ZeOU+bc^ zG90*%_R-~h@<~50H!L-ToFq#Uo4ZU_8a++6Lx0nAf;7=(qApQ^!}YRl&rLp)Ux_uWg(z&vn8Jmg1_qA8^$ldWJle;~dzpyQn|ZvK zf11LnJADeT znjfsbk2iTWXJ~)CXWOaa{rhm1*+Zz&l2-FrS}w;lDp=P~jAAE_Z&yTI>TqyFxKVBb z-SHst+hJ6_T@f~6C{t~i$0bA70iiW4xZ!Po$c#}X|FLSEXMzH2Mtpl4P5iv;=JYHJ zj@>~9zg{&&(cB0iA`OU$?N5{&U4US4vQlaMxrH|~-6i4XmNS|Qty4Brw*~WU0<4>_ z$^9q^i&}DHjPLzffnmm4px9OQD7HQ-9#ZowuSr4Q(U3aWF&gAwUt*~O&O0%HeDKCc zTl1eXQO>^pM$cDlHa`xMo5{MXyQSRfU#^Rvgf*o7X&Sd|^lb$z8%tznM4NLqbAEOZ zyko^4swITyC|V#V3x$4y;U+gscXFel%DK#Lz8wd_soiJfO^E zLMHtjj|jLgY|JFN%aIeC^K`tt$fI)Lb`y_iI8E~}(5}&Coq62*oOFtN7$)LI3N1A= zEJ2Iv2?>4xaM;vwK{G4yI5Gu&D9r2*>ZKP~4~W@Vz2p-yKarb={8ZwoK%eTYTuo3O zuHz)oYCYq$J-p(Jho`}uCKS6Nl!^?Z<0itFtC@>InyN2?&hVBQJrvc=*L<}Kz@%Sd zn!biLFK|R_@y-v!F8uVNdqHRy<+>W1LxSALNxiV<&8qd(xoy4Z|igfT$EaGBF0gSFW>!AB0mqY|=@%!HDA8*jO0b5Pe)m@MrB{b73jwfE(7 zxA`<}6Z+Ip%#FgXXB4ak=cfs3*L@K~9)**;jTzhI5z`H}%5O-}>RcXX2!!`W><^cyudEs3%LFVMJUJ z+;{^Xml#IOc-23T0uG2x#cxhI!%W zsZtasif^RD$tXrFMm*h6qkQI-}06lId6kZ1=&oxdxIMdy!umc*`R!J)b>M( zIis}Q&_c%Va{B}B>WIm#UkhrI)Lu%W9LnXhs>Db)O(7RikGsOUr!C?)hH&7RGZrtr z0fhv8MZ$Ra{IWTA`*U5iP~!DhoLJkarC135wC3wGue+&0!}J{MGc62z3oC6vVY?tA<{C5L z5FcBTeY~Nx&-b5T+$VM`7^pwM?- ztrnAVrB7yUodSG?>o`X|d+qpYqNo3A^c9WGRAS-d;n!fquKnAAh#u9!6wcKyuhFyf zMp*f~-Bmd4I25w_g+^i{LU`euIBy(@t-^0k8OA+9g0X?H`BXrU9|Fy1t6klEV3es~ z)WWQ`f~;`egySe2;wjK+Kr*kSP=QatIrb$hs`Ox_?^^v7upXo*oXT}c6u24;VsR>( z$=lfYR*sRCWANlKW>wvOyZ!9VHGkpXmqKRG7}F2WEq^%OiL#|F-kPTWWK;3EC&tvc zYJ&TSb&zdc6IR`}rL9U1Id3s*%g zqEQGJ4oi3~QFb6z`!jF{PtF(T381G7Bi@|_Y}Z;i_WV{s?25@#6~#P|;ZW_nkB#Ti z=3^QTpJ!Ip?7sXK(HNBi?h55a!)138ES@>J!pK5H*0}6D@Z@kjLZuOKi(`4%b#!8f zaeS5D)PI+6`zu42fc-2OGK_jZAXE(~GEdZ%+&>4T-t zTyqxz?}d@c+R9iPKnimz@6_kMz8`yET{REVcbTosOQ1_*Z3k6srSU{t%9AXACRQbo zp3Zh00b%^e0Hpr>^;4W9FlQp9y7*mFA$kVBL17Lu4AP!ij3V7lh>kppupa2V;ph|L zXaa_1(N2qwBQ-n(j?x-@5@)pg99m?)BT(nFmd(YWeG+^$rN$YGB$|HWBcyfqrz;++?%^1dL z?8LnO-U-RPr&J?q9TnAei58e@QNC`0#jL?UUAAn^=T-|p`0cP7$V+i0m<{qL)0FwZ zM8eHYeYwJ_%x}WIk-RN2oS$Ltxh334m89uQjNCJnpcvL4SQXrj^5RaE5p`i??+%vwV^03^ zvN+(r6FgF}c>W`t1<7-o{%VLyIyo>si>)!$EB^kciGgt;)5MNVo3BbFfuMhluzING zq%oL_#B*3I4n|tYXpwD+?}>79lan1koqv!mNH}OapMJXtG=R*h)eRQ#UWh4S+1WLk zN@a87kbSI_xDd}zCFaxIkrKHsJW04DXpei#kZ{yQ?@onT*M$MzBCQX++7yIVPJU?h zXky~BQ7aH1`s6k}QokRX#bATiQ75t8})Qn<^q=b4oo8ULm++d66}Z?Q^GxmBI!d}lSoa`$G#iiD!+3Mi`^R7CgK{Z^2 zM_#y4g|OA&CspvwrGJR&$y9!GK-{WUo=Lu)w~DrI(j*p(7dLOepOkaoKb&*w!>BSAfWBN*{-ADBH>sQWF-0yAW za=$P2exVWYtSS=lk9JDzjJ~9VB{A}k4S63~!(@YY7dAk#-}GAD%Y@JWauvgII-c?z zBFc7@1n#0PBNb7JzKcW^WbZ~EG@Bc^n%edWVEYrsCHNg|u6fK}Xufs{FZe2niVMe& zwn2|{=M+)@L29-gh9E$54&mDlSSqn24CP2lVr{?b6iJt~EH}O=*+1mW6_O-B_6n$a7MZhJO ziN*SACAD0UjCp$zKh5Iig`$wR6e}*_x+<}Dh=au4_xaS!@cJTSCaKWrxi=h+o!yJhq^?&WF@oc}6t5ueo{T z+1CKO4{J!L0~vDH>DAahC~TE^!n%NteYp2t@h_y4@l zFlQpxsx_X$#Hn5q@RjVBj;4o!Hm5Xm{ilKzE1 z%H>POm0p|j5);^t;ePI0dn_(}&bfNfh1<3fBJ>ZI%+ZtC!ABxY5Is7x%BKJljsw3* z^7&F`gji?cU+sP_K*YSML85vmp|b%p$P8)8@qp}c^dBg=wFuQh;n>TK#bcbTT%t=M z3>2cqcOjeT^=Z{2@&P+`C|mreGW0uBcW1zF5m{v5R+ckxeZ2th7JhR0_R9YF&zC~4 zE=#ktnASPtkNp`jzvH-3!H=eJOj3xou3~Ql9wiZC6S@6n|NJ;Ywq!Zb3k1Sgv(aaB zdB%tulkq0mS{`->&Q<*pX?_+|G{kvav-anOF$7=G#$Lmwe4hL0&hL`DIt zV7U=~+Luym+O_ah&cpvB>3v)+?6>PKs5U;2%VDJ-193egKm+5Y6?{0M(dvXzorHG6M)o2;#e#|O!eJJDKW!(+`<~Ock&xMZ=_DZcO$pe-28Wqz0 zEcuY&0JMc*il!;e1?c;6cT3hVgj4Z0z4CDss=qyMNhkyg#{9dTLF7#oLu*JyIy}5^$S)SC0$FNts(7@YmJ@R}2JdzOh z_2QIGm5}rRAsZxY_pNOD52Q>snEJ-7bsMYGHZ0ixfbmuo)mCi=FK_YYBgxHKu3jBl zOG46L2Ir7eY6An?r$%etM~iq^k#52F^~OkS+X{$Ajei<78t?Fwz`OjV7ex?PR2cBW zY6jri9Q8}|{)-OdX6O=`H5qfQu2$c?opLSRyo4c=RvPRSiSf-1tn2j&>!?^1&UcKjZFs+~H1gvj(u8`T~~=>W1M`}Tb47<~4j;^Mnp z9(&fGcuaGuiBw$OX1_0ob1H1d-t8L4=CIZ)=V6n7Jn+e?S%!2WZ}F0vs~FHEPta2Q zO)%1x1v_E2Ni!6fujF%V!CTHb1ZT)zlJ1DAAsyeEqkeVG|7xj|rRQ(X=> z8j2XQICb}T4~`za322InchvcIw_2}6BsJ=&egEPxUifn!hX>0P@P486z^@tqd5}&v z?$kONV%vj6m>KmyF2JZP1eQ=+h_oAda=Ia0KBVT!9w#x-ky}%6sG+6l?0r*JbQMUt zriQ(VcQ(U!?We70r4&sPE2#h)T*5^tboUdn-HKjg^Nn1YhYZ>l_uIE`Wy zhZCz_phl3GWtCp}0iA7DqRzbI&$Q_C3~x&xb{V?&jh7V$gTkn@Wm0xfEPHXCc02Ceg?jtly& z5yL#uwZBGtl_1?VL_=_GxDeBd=?p}JHg!?QS}0Xs6Vre48)831)G{A02WOV>k53>e ze6h$>`bL^3!Hn?2pze|4P3I{xEmoW&NkAak=@FRNlm!1R`{U`jLM0<_Rs46`{IZ}q zrr}xMk_45X$)9YE8G8H+ul8oKz_j(2uoG8+r6QAWXOAi6clif7FqxL6y=_B|S6TCu6JUOV@Ey1FCuQZnk_sU5Cp zbS-9aCE|rv&PP+4iT2y~(eb`X(g7`VDH?2-r?wn_4H3{S737-7yl91fmUi{+eb8x# zB<4R+k>8bm{r;X8;j;>3y3Y4nbQf!Xe2iCoF8c zxVGmHE}}&e=6`i;usH-Md+e{~I8`ZkEXbC==e(N3NV7dAHt~(09*|bB6`aS`9*1Zs z|Nf@S`v#vRMa`e|f(f9=Q{yTvO>=hMVFJRZEtmehorS$gjJ_7Z2_wxRyfz^O)-(;( zda!)Do7KL!T16mC8ZyUET$8b;8GXu+mw_UB~*V!X&QY5MiCb%$kMg$lLvdEJgF&kqGG!ik&{#0oL+31<)RCcF=il z|5_A<7g1h<)LI-Z>7F#+Tyyq%OA4V$^Pr$1+GISisNPVm_VMUwZb2UpN$hRy51GfZ zU*aI5(VrRlKkZ#*R~^B!#a#mgcZc8*+}+*X-7UC7u;A`4!QC~uI|p}%0|eK1a^G6- z2fWYs+gY_vm4VW&7vbpu!ajQ{Xy z6}0^5)@|x9WaZpnE!qE>BNzyJSC;b7JKetAcfiiH~QUaKxX6M0YN4hfQUBN&Pho@&^P=e>O5al&44ip$SJLapGIYBrFog z$V+;nJXNtb4)7hU{x@}0-o&K&u3z`^Vd_+_ec>YS<06|nr`pF9rBFZk2oK<`U7|Gf z&Qr%FSttnx7F#z3H!|5KlO{!sb)HmlbM7xJnuEV&=x;5fuU;DtRC9^F8p~sNP{PV9 zfLZ&TW*M?{7*?-aOY86i)ehuNCOlWr;ilFU&FP1ua{6yqAfiw(NtP(A3=p=)pwGzL z^jS>3+{dlJp_mGGqYYkpKd1uRA>OX+(9DyOHeJL4r)KC9#v)FI-)`A@mD@b=iX!c= z>2BVchn@brA%0*Zr|b5s)@U9Z!qYXx(hvzrW}O^1{<@zuZ*M(!Yf<8_%tB5OE(dl} z@Yv1F>sG#8?EDBw=KtL0P{rMEr;w-h6rG`P`(%buBEW&zW(O1RhU_RM0jn=~>ZqqF zT)VyxDJ<%t(X(~H$rerN;##(GzLW$DnC4gQ_fjWaScJSOpkmCN3qXXyy& zmvc(}R`UpYA+BMqVj|Rbjy3DKmbp^Q>d zkMR>@Y9mIfL-WGKbEXz@>5Rsf?zWVTqmnKnl>Rw`wUI_}jfZ*H$kEWY6j|E-V@@0) z_~4b*xQpsrACS8U+H0BBg+)caJWZnchT8i27B{KpB(lsRM4 zKWgHj#(*RA!Pq_WMDP6ZM-1D*9RkKVrwNw=FI(UXjMqZmCSlpV1Lj62+Kp< zQ|2C{7ZWV7XagswOW!Mx-#eKDYansAAwW^nilP_F;RnG@5I1D-^%GaS4p%7oM#iu4 z(5dIWJNX{T12Zg(v(Rrn4oHKN9LL1B{ii`09UWI%FD=(bkechyNk-~C*b|4*fj%=+g0CMxTjHisM>`Ecx_E~q6z}y0r=!} z-@NI`%Ctw=2qccD$t1bdHh56zs%ar}MV^ z4-fI#6ay2~h(J|%7{1(ngLoMPtv}OOl5NlSAQC0h9p-OTW)SDQQIg&f^Y2dSJl-b% z6!K3fkL0(5qd{N4nnJ!XgZ5mYW&e+RwH!|4xgT6v@^VFH#MD#NPYh*lP6>apHP?c) zh_taz?f!!2Y1fFzkRwfv-gxUfEYR%dZNcPjr)51pi%k_$N8Y@U{hGM^2@K%S71Qqh znY}?q$S|gqkt@)k4ON!iB=s$ zl9wOddB)k{%v0i!LupZFE!eg0AYs1d0hck@a zn%oF?g}*U-`73fAWS89^3M=OPz{f(F;X;4C=^O-@dz3K$ChCh{AB3)3%`xVqq=ZXZ zm%}S-)4tg9{Q9&K+m5XypDR0K>iqug)^+eO^p)Vt6Ruj#`Q-*LSziXePNz{v*|WhiVpp zFuDI|+g-!d-D0;qk`@*JMK=K+Q;&Q__RRI6f_nG%1#G_JS~3&)q}5<~jIqLAPy|#M zUSMN}mhI6%HL9~ub%i^(gfNuF4v47p8ob8%-dVJ|Fr)V_3)}Q}n0C127k;JcWlRH& z_=FdxDusV{b&`o#)vl9M0)YzDf=KLr*>R*SVW>)dzxLb}457MAW1R1X ze*ZU&oSCZ7T7VkmmU2OL+rh6^P7?NoA7;Tl(V*Q|Zq3O3XWXuz3^|zB+0k9Q=0}y{ z?kTl%E9M0}{kg&^WQY(lqcv&?PKK|$fsWP~Or@aFzAkG4x-NCgorIhl?ULEuT!xcys-Y_& z<*WoeP_N#PmyMRI%f4b%V=oZ0)LyrU(=aj*I|_FXmFnN7dmE< zm`+BXZ*nd&%H{TTK^z#_UTzP}%}PH-o%;L3cb>}1>3fOAL&&vLoxEEmFj+k%4(%-F zj@`{05{f&KVrme1t4wvK;J$rW!k){jt9iT834!d0rIAu~rHA<#op=?B{aC*I@_LlZ5hQ)$(cUnQwgqZN3 z*OiMC*YO-RA}z{CGTLy?eN(~s#wsKhKRMZl2F9(=L=ig2S9?q72wHbLrK8rC4&OJv z0c>p6ei*uNU9JOdh_Z`AhUU9RA2-_D8-DQFve(%aO5hQv7kT4SSt_>y4CJCElx&73|AMO~}7Y;j<@;eeJJHt#R0rM_Oo@;{E(7xoQ z$3BrSzIltRBAig)M9gX_XA&AusvYxqIfWgCyz;~4H9C+oMoyraL)U2Ke_>lMV5)@6 zF(s8cxA&8|8ttio69ePxyXmhsxk4V~KN&IBWb)=DGby`Cw`+Kd7xXu6iM4}RtOZ74 zIn<^nR0Ua)MSzB7#ql_o%x9+%FYDqq;D27w=h^$O=%pR+l^>0vumnC*#WDyO_DzDW1>C1vh1IL2G;7*{CvWp)2{fq|xlYNX3zt-OjgWECwB_I7n7 z0zIEbTpBxTEUR$JRy{n>8o9@xg^|04+~p0n>ccpqVbv;`$1XXO0#P1+kT5@RK%$vh z$m4B;FA`yh?NISF^|$cv#p+#hvHfTgX5jinuqqH;LbE$aamO$I-FaBtSJq-hnT;c5 zad5meg0xH99U&@4&$~*stzmDs=4G648w$c?U&}f>zaf7%`sdL|&ag0V`^P_&{IW{a zCE5B+xo_VN5`?ad_Qm@j6{B4)`w|A2viWv=o~bv-EO(fY9HD17NOK=|1TVssnb=g7 zvI_!oZc>0f0FGo~XVW%T+ZT;^QVX(ewKUA$M#gD@-$Rl(x>Cl>EieOOsRfXCs|t2gGUcLO!JF;E#CmLh}=h=J$y2|Al9#HArKx7E~SN-+^? zS!cQzc$~WXF@k`RU;B)7RIhS+!1n)0gra=v&}kd;(&$17^tk&E2|VY9jE2bgzU zmb+<$=>z8!L;FdmXXlVbjzMZU!Wy7H$cNz*@dgX@%D8UIyJzOI>R(tmbADNvrkOW8 zE~-$fiO!v4r=}$>vB|h95FtM2i{X(1S2Xl!jroa94h!*TtFe;Q`K1ztHZd$!@%+s= zb6gCs^7Ysf;VzqY7mRA@F;#(PBLvESnFYlV?875O0{3<&>%Kt$i?Y&6Ab|`;Nz!7Z zwXEl=)1GcQy@I1SNQ=QFO;N2m=6Aq=Nk-{oY{qYnLW6nT!)RuN-qGCQdXVguc!lYm z?x59Xkknr)KdrWO@;Le3GQc)E9X2yp{0JsuP_UVMm9Er#863(!)gZMU1T;CK1V}kS zGqe5&UxP6GM;mTq+oS`l1c@C>ECqYzj-9wJlo7(OmjgN8o3U(KS`2+9z)NgmbumwY z-T9zvgP-PhEje>t_rn3!4!$E;Ex{rjU0H=&Br6_e2Z&Mk93Ca#Ga^s!{ef1yV3_>_7=&9Sp%dmUM))Vz%qN=LO?W42fFl@kC zE9ae?cQS(q57`I9MQ;-5O!|8iI02cvM}PiAr-(q8$00{R!TXrt)v2vqn~!?4ml_r0`9oqb_N+! zfWd6Gsfm{DZ1`#4EGM1|sD3l4=9Tq=hk2sGN()ULuKRT2OtPYQiT+Y(X|WSE}2Q$ovhLD4kd56=XfU-HZQ} z)4XP2TR4<@*(bPJz_Z=eqItXXvfm}-bf!OVGI5n_vdHT2s#2E39V!mN{csXp+C2HC zIOSN5r$=sN&q;4{FYaF|8Kc-lK_8SQc7Xq^sXq@7<9pC*-N@FrqSO%S<5Y85>^v zdOzjyeZ+F%W)>;+8LN=6SCQDsfv(hS1xp|HV`&$TT?P=ARnUUb<|`jvn2v{1#fDXa z+=2Ld7!8xRLv1m`-il5_vTz$~qamIaYiGph`kxnQKLD>$Q=$EW=fSCNIAHu)Ea@^6 z9;XNIDYG=+{~lXhvqW%TRQPRJI~1jh;<6c~VH^U9Bdbt@3_h1f(!I(6rf}lm>csjy@6eI@si^;`=^f zF4n$4fS7t`kIB+8QXGBL{E9^&6)*)I19LD5i_sWDWzQL~tGo(p+ENv{gC^JxvIC-* zD~n4UR^b}X*<--xr$1_Z%ym8V8q6ejqDbti*fK*)2?rmJ{Q*8p$9ZOGG9$A!W!tVa z!{EW4=gbg-rLtaV0Em=mqrZRQ;6-*B>)fnlm~#7W$62kL022e&sdZ&%I_4w|debJw zYA?y(bt5-|I-{`H?!EmBC#Syv#7#m8PcR#K$SX8`Tu{)_|L3R8Gvep@13jDH5j>E<`%$Lo30ut?WYR%dhKQLvnBb-oWrActqF^2mL@6H<3Jam<5gvF>-3o z38=2Bl~bxf6S%mwU4ucxD|aYA*6g5sd*cDzqPZChMrmEhF7`!Kv-|8Hl+UHJ&U+0|oNTnTRI zM0s@?2=xSB@e0Hu0ZczF+6GOR&#GUkKMrHvQ-z^HHY}Z!hsmYt$9igU!4xw z$~3s5%fz1$$~p0K5{h%=l8o9>Tf!AnN+t0eG5*%m(hP}m`Ip_mBGcEI(8E^6+x~gR zRX||EX=1x&cthIlY2u)FNrP<;NZRB5vB_~;$BU1-L>k~p8#A<+OiSJjVi#Tb@8?N- z<<=?>r?`EMVNcI=fsQySRkAZJPLTWg$M)$DRlEX)M@jp-Q=VzA0_Waf|Ap$~##>%G zleJ|*Wg4yQSpC!OV_7$7E z#KBpc;<1ZyKA(kSS@{+pn3YSGLgZ07q`k{GZ(@KlMd3_(ky&ar8XChQBEY*(htyBZk9C>o&FSj&1xd5 z4QvSTL$!GlpqxW-NgJ7tP3JRhQDlEICHUOLBBeWv7%i&G$BMI+VbnPLCtiBFo29 zwYG)lGBJ}S1~TznQqx^RRv5W^W!sQ^^j>$O$a72dPH%{@2LuY&iJuBf@l*l9<=>-7 zFlcXaDO(H^;OL}JwW2I)mE!2&`$3$%d3|s5Yvm&J;ymh!p@v4SqN(f#2J2X+i7xV%@e-9 zW{;7^$ian+ZqRdMbyH<$C#&u}uuf?YxTHICTBCA1j+*blNM^fV{B1@b6bjP#dH9Xs zJ3V@8>BZsQ^{pCfIyvh)-q}xTj1Sq|+h+-T2ACw*JCPCS43xu~28rE}BbJuQVCl~e z#!zvs-VYe;l&zDpWn6z^Js-wv|~Ea zDWhb|h_*!Mm60rEMyl@il^W0ZVWg=!Ek1J~B?kY_*7ecF)t? zi8}<<$k^)CN&8;sKQRjK8Nk`7&mUX($##BLjCB?W%(ltxl=gzizUTTz=ho_|>~lO* zWs)fO30Gvy`v$Zp-Zoj2Ic_bIGE`RkH&RMEl||AxT)-@ zm6jZXWg)H@0T5uI?Slv^g8l&IIzd@N#FD=wf)2|45mWDAYvPocr*kOMUQ+f&?$n?h zZHcuwUAi~7XT+-K0TA3045qU%-6dVvFC3SyRR$03D zsNmB`6$BXWR|8rg;Kl%FyZk=7cFSHOh^djxz*XXFEip{)TFGM|OOmuxuNV$UKd7ny zMFQ}R|0F_8PM51TC)HR`f?z-rtHW4T&AgNA*QXJvf4Wp7zy1xY9!v&2ZGFsh&Y z{gs{y6ASIM5{u?v;DUFK{Vi(5F;{X=2N5JWX+y2DZf<>fp!erQa}f*-KkMH&0))h! zI8qiOL(Us>z;PD2jTAEZgtI%12#W}YO*pAL033tD-5bTc6VAgS=WOsO$*J#5sE~@^ zpo0xA^XV6H#2aSc=fNq-&7z{rLM2|+^cdUT-3Q1i?qllzQmU(a$Sx??{gt8`3QIf7 zr+Ka4A|+H`u7X{JoCZTu@!#OU(h`(K%%oyRb!i{Sc#!cJ^L1ns3hQ>|RBKtxbmi+S zPjX}F_2j$;6*!2f&h&6ogz2tXu*S%^7F0?X66`Pz`@T~9yJb zxsMbBQV+}DlI#9X`~2mO^|IKM-;~|aSX4sbpSa7ah0l}74G|7&w(3XZ1V{!*j>=z_ z$11s`7et#Ob-S>q{YCANeM;6ZE3KCJ!Ga%Q?q%`ZQ&pDA_PI4tPtkNiWav`O|H-iJ zT7L4#4aq!=x>Vs%TDl?zC~53yb=Pb_~srT0Ul3U`hq~ zBttsw80RmWR?I_P0E;G4kpYZwFuH`(vUh<5Q%9FA5hAHyn~J)gWW(Rg^1k{kI)K0S znzJ^ECyu)~@o$RmHba_Y{g2GMgSHm_5I%+C3#ax1At__b52d8w5V!g}AlxdA5{p@c zmmcuj)*eA0i61w3$YoOrn&jCP!B_48*MkQMWjI^wuL`Y9w0)4x{*=WOT25y^LH(>? zz>xRj&7oT3dNiW!*PmjzYNiW|YTRr5FTErU(!&EkL72ohooFZSo0&pM^bSgV zyC^lnw;X^|^t%}2B5Dj;8{phAa(+JPq4hKN^9p^tA^e~QmrUn^Bn)v3gXXkaE z2a{EPn)aDJ4FmCWU@m2MKXJu*O^v7TrB+;C-$eCjq+12 zYZIQp?!}iDO+z$BLxznQBB=){Be-i%emw}x<`+Ds0N=nYk^-T5Xm*Ij3^n|qK$3K@ za(`;0^hho#VWO`leH1~VIc5nSr_82jzwQpy?WVzEY6>6ab|C-CXx>>UCt1UKh`kT$ zRz?cd)g^6CcOOdIZYe>2BS3t+d4GvFmRZk{N7<#hj@BP%aBr_}Yhuox$?y6dumQ0+ z=?B$=&bCuSn0bWFI{TqMIWcNQMwHN$EEks~ovN?i%1GjW4xyslazH0qb4|{YGl-l{ zpbYUd(v~DVZbY}ka!olF9!x594c5e-(W3STr{NVTff8{HF`mzQOKCA3l62scMl~xv&~UNzJDxR&Hs^nFIYDq&_3kB(ach-h%aFc_gyN zIV?Mi>P8dN>IUnc3jKxYiYX;pnj8Tzk9c|b>D&lUAVeFiC1i2(?zLsXuvHQ&x?QzJ zXunlbRJ1r-sp=}X_-;P>g78p#U-4lfWdB{{K3VM5FR9~K%8{8ed+F^^3irW0v15*s z^Hg>X`ox@r8k^1>7#R#i86BxJL^<@+xDWpPfSI=po>K@+IyK4x844gd+z+X}5y3K5 zITyQ+cHK2vNS-jg$r!TS;vJJ#TfCccF|F*(xSaK9sR;$>L@PZIbaj z3uN5IQs^coB(@}RNo$#8(#a}NyrI*wp<8-V81e*F5N@i)K*7w+2A+?J!DpO{x{U; zDR{-0$w%22A0P(gN<>f*_N7^ChEFBCr13e2b}Zo66c3Cgs~jM=u@$7NM?f$9XH07F zatTxB9Zva-JnX0AA9mVs+v4524vF4rh0QBQlNYL_Oqt`&d$W8ewQLb<1)b6=$VycC;TW=_!a=>?YS)M~K(7x|aoE~w6{fT!mn(3)07IN8pWX1EXrz*5mS zQXc$>08j7Ln{LBcxJITO)%!^VB7M)(`AT?+ytHe5Ly$cyk+9(CirwGIYk~lYAvMSA zT6|Opdt@E<=*g=mIjY{xLBr%|;NxOYbz=O|-MkXmB; zTuDP4S2ytW{cM^>txAV_>*wzqr+o=D78y@N#oXn(9(-)_xw2^Et6rXeR$YMGPH#^v z{Q@yKeB-q8oz^K`WOTga4$HZv0Fns=A!O6(JnhmzKh7SK=0RlUN*1rS2p(DiLUMr{ zAejd6M`uDIDm*3*Z|InN2{pVh5^lWS;w>p;|m-U>a9;)6)cHY zap{h=hg7q;%6P60P)x*NHBHz7g{>kE;Zc0@^ErRPLk4tXzK1Vo>cUi*teSLoL$CTQ zZ#cUOd`XzQT!J%AU*?obxgz8dhR#@JIcOqtnvSlj;S7y)5IXK(QA2sO;C3V`@^}Ag z%>!-C&DUWB1nSH?TE$xnKzz?S6w=}Jve&=ExH&mbq0o_>wM_`KVA&XAY zlCunp_+27-Q;*1+KSiMueE~h&8P(VHs9#l3?>V80dl<5S+>ykLJO;crB4M8794Ai; zqAC~Z8-d}I(pSYOwy)GRRtQnu_v<=pwd*?OK7sB?%RT9dFOx1t%QS=srcFBK`gW?B zug4FS8Zg|$4#}PVW9%utUvt-tznD9nD4sBLt@JJHd8l#31eF;VBY}CyOJkoQy?#{j z2?^6BvWLg@LYJ0s`3wwrrlkKRL*hw22#H}7=sCIDmF)@k;u>hM3=pE{VGW@UA#I&8S(%`4}7t8-%`a2;L+DV^ruBD(5sVxxaV%r+o$$ z*tgs&H3t=z?^hIAeEI?|;DA*2jz=EW%LJGON9QTiR4mES!p60!JP=VMb` z+(V=kgocmDT3Ie#MEE}2n0RW`(*EvO6Z0!M6Hp=4Y9V0lI{$ocW$1YmyJpP1hh_>e zs4i-S76oiIu6G+x`*A+4RP$8P>gv88EpaFkg&`o&&4>uz*(Co_mWS}xcu??Zk7wF6 zutSM+Va4oxx>O|s6LguByNS&eP)k<~LzXPH`+J?-8>bM#_v_;Z_Z&Z~erlbnYonE} z&&5rWg#Nt-Pi6c{z~{oLd=>vCSj~}B-VsrvXT@MEOvi;TOVggaS)jTH&Pz`eOG30k zee+z{di}yw(ieMiuC@C@^8To%^SHCJNCai3?(yYgnjfSMG>(568rFs2^_x!Z`5Lju zne5L9Py1+iPABaj&g2PnnO}0i=8scbk*{7f@71|qD!=@Wsx6R&s{h4NM#nBc?rmPK z0^Fn3)w<}%kQfFS|#!kfw-FqN0_}~>ymROleVTn#C7~kou8C8ybA&TPp<(RuiM7O5{3oc zXOO1yuH++GX@%f0=hbc0h-M77CY518`nQ~Wd5lVy`!Y+uS6%nAaZfu0!s7$|yEtHr z(uI>t9PGGclRW3SQkr`WeV!lmrt@-?dwT(u(i!k_Dqn3_Z`~4WQNZV|ZpkoU8Sn3i zsQMPdFoVY6w+N$y-0+4U%|0?5Ax%kihAy+H4NxNWh|nGCkuB^2&scYMuDI0sgeqtE ze#hz-#9R7yL#7PEV_AMr@l5jkcU{L1$+t=gqC?yiCg8ebhbUXS#1HIOox(`3~!I#oNZ}-Rv(tveM@1G z=QyMNfq|W=4plTc!}Iv@3AMPcOLp_DJK5u&2KZHP;>vofs3zYaC}>;iQ4`l|_3*O3 z^s38tk*k9H1$rc+ncs6hn$RJusb^Nxhf8;Q?X0;9M#GDQE_{`K-JKEvd59#n3-|<> zj8^(|zI0KU-^@rdjz}8!E~jYUO1u9=TocSm#;#wk#exbk>{ud0L+Es1eZ6zHFzlMj za;cE?or^HBVCpu17$t2qd>_2XSfO7Hq_<7$kY2Yxls_q{ZFb|}+7ls*BmY6XplvA> zIbO^eq+)m#D9_$< zV7kR-`bo;Rls(T_$&Nx>hsWo&F^J{m`a?5Jk3kdqX7Q)yY*!2`oglZ&c5rrM!K= zCY_le5$niwIa=->>GY}njqUA0lb{6As8ULSfqEEac9T@++q{89^rs;;_3QDbt=8DA zzPSIPtVL0uB~d>O8dchvFa#a>-w#^QVq$rn6lkmt89K5kH~SfdK^F;>MD@9T&0(`Z z_E&VjX8%DOG25$WAc2PV$QoQ$KRyvp;FBxX^G8gn19G;$j0~q93U_-Qs)<5i*7D)9 zbE?NT0&rIjcv{{AY7a36yp#iiigMEmOwtL^%5lJ8 zSaHz;MBEqete8(4zhHuu*^O&fAfeD=h|-}PjC0^eCzMu(@h!VTiuUkiu66avde?PF zd3ovfUq@cMKgVxW7g^6!srS7z!Gh-&76zxVB!niEYlF6xsWx>y}* z6NVt>62R2Jz_7WbJXvpb(YauYG|=d7TF;64TwW-))nUWj<1d!Mltv*7zsdKGp)417 zI)X3Ikzrj?y?mArI}3Kd^?}?6FZeQG{i{lEzE6~tB*O7!&VV|=MJT|X*UwAlQ1rl$ z#!zwj9MMhB4PEUFcu>?AA!a(B`t)WPaQKLpl^(}|i+!JN$KfqP z3tow-;g%o1MTVU`D{bMoOh;RwMrVDV*X5k5g{X*e24V0dI9R!Qa-DENzQ@UxYYNC& z`W%Nj1X!58#z)ysRn1~0eJvgmmx34EIA>2Z^&}wToTf1ZoJ1Hk_QD!TKB1aUp~`*< z>IHMB#)N8-MbbK7O#Y9=peWC$mb(0tqfmRCzLnsq*b5ydSAtxvFGyPh`%PGvTDFMtBf4eh!ABR$+=*#%N+J8ZDhB1Do?6Mi!RsF`Hf7K)3o+sV zwrEO7qG5=XL^>@hJ>e#JUyu&CWB;s3ub!YA!2mc+j| z^B6BZ8nQR?6K2m;pap`~l@ba>7~=5ua@NH7zA3N5G>T13(*=6?W+=05#&oY z0yvydz8KWnd~l1xc+5w8hF`T9SeyF41&U@RzeCFQDt5jw$%7sP?Dpvgwz?`$2Z0QO z1wG-s2*Li zL#ThoOUPzhP@4QqECifmRQO>xzWp=G0pHY3Q1aW24(FTf&7CmFg>n>d=uS#Jd%_$9 zmOB3z)a+BX2^a3dlAP2J4(bOO#3AMEoQoQ#tO{O{IW2T=1-<$f zY#8sqEoS!Ns+>TblPG+6&-}XXpJ^JVpkLk54*W=6F}DH~8{8lVz|l`=JkZaLcg(M6 z|MM5>pqj2|98~g0R?N53121l3yem8iG^r#Z%`NdNqk}@>_IP$;o~m##sBy{seW6Di zj80_l+8!A2>sx;I4HnSOMg*>o|0x^;5QhsF$V((;Y3$Sb=jgd?{$(z5$)UK~+^5zo-?5pk`(g$*(r^55+KfC&5ZZMwJm9xdjL4K5V> z6U|BdpAXe=V!-f@RoJRBqk}CN=U9z}iAPc}a5zlS{JI}QVGfqv&>@tSCPWZ55Fj%~ z3=p?;{s3vmXa^?)g#J;Wtgd6Ey&Ics%)fweGKQ!`EHUe9$s!pF>`D#}a{4ogY5LDv zHhF%2i-(Z@mx5724{|8eW~Xwe-H}F!aCWo35pYn@^o7Ao;oK!EiKRUL1n)`+cK+}? zmeugO*L}xFkIc{?28FFTMZ6DkyU<(rs9qEfNjC)!cB3it>#$NxK}^`cx!s4d;r9>F zfayPR58ojEHz*XKr;xN9o5a7E|4AKa^oQ*L;a_|vk^~x2uuS2=gL*`g3l@w%6HgBs z3N)!;u;7G0?4}g|8vg)2?D#}$K+X%1z=M8&S%^va*LV-~u)aZRhxp$cyrE79E9h(V T315P~>kTF?t{_$;Vif#8pYitM literal 0 HcmV?d00001 diff --git a/vscode/package-lock.json b/vscode/package-lock.json new file mode 100644 index 0000000..bcd9852 --- /dev/null +++ b/vscode/package-lock.json @@ -0,0 +1,4852 @@ +{ + "name": "mcpp-vscode", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "mcpp-vscode", + "version": "1.0.0", + "license": "Apache-2.0", + "devDependencies": { + "@types/jsdom": "^27.0.0", + "@types/node": "^24.0.0", + "@types/vscode": "~1.91.0", + "@vscode/test-electron": "^3.1.0", + "@vscode/vsce": "^3.9.2", + "jsdom": "^27.0.0", + "typescript": "^5.9.0" + }, + "engines": { + "vscode": "^1.91.0" + } + }, + "node_modules/@acemir/cssom": { + "version": "0.9.32", + "resolved": "https://registry.npmjs.org/@acemir/cssom/-/cssom-0.9.32.tgz", + "integrity": "sha512-OijrAUu7rrJhSIoHNg6LMPS5e344nwUHA+1EFYYjrh64D+GmytUsfBQjci45TjT+rd5Spsp8B5xsZDT+TgyXXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@asamuzakjp/css-color": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-4.1.2.tgz", + "integrity": "sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^3.0.0", + "@csstools/css-color-parser": "^4.0.1", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0", + "lru-cache": "^11.2.5" + } + }, + "node_modules/@asamuzakjp/css-color/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "6.8.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-6.8.1.tgz", + "integrity": "sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.1.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.2.6" + } + }, + "node_modules/@asamuzakjp/dom-selector/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@azu/format-text": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@azu/format-text/-/format-text-1.0.2.tgz", + "integrity": "sha512-Swi4N7Edy1Eqq82GxgEECXSSLyn6GOb5htRFPzBDdUkECGXtlf12ynO5oJSpWKPwCaUssOu7NfhDcCWpIC6Ywg==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/@azu/style-format": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@azu/style-format/-/style-format-1.0.1.tgz", + "integrity": "sha512-AHcTojlNBdD/3/KxIKlg8sxIWHfOtQszLvOpagLTO+bjC3u7SAszu1lf//u7JJC50aUSH+BVWDD/KvaA6Gfn5g==", + "dev": true, + "license": "WTFPL", + "dependencies": { + "@azu/format-text": "^1.0.1" + } + }, + "node_modules/@azure/abort-controller": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@azure/abort-controller/-/abort-controller-2.2.0.tgz", + "integrity": "sha512-fNAjWnA/nZ2jz31kxR/AqRaUT8ewHBw/WuBIosK0moMy1C9e5ValbDfFdIxJzVOOYaYkV/b2F1S4H/aHiqfVQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-auth": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@azure/core-auth/-/core-auth-1.11.0.tgz", + "integrity": "sha512-IUZydyTUkDnYdstOW9pFOOUQlBjAepK5teihDE3x6yxsPJs/hsAaaYpeGxdxrgtOiJbBKSjKW7MDk7AEhb4LRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-util": "^1.13.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-client": { + "version": "1.11.1", + "resolved": "https://registry.npmjs.org/@azure/core-client/-/core-client-1.11.1.tgz", + "integrity": "sha512-2QygG2F76ZpMP2eMztiJvAiFMu71M9rDeU7vO/QKg5Css7MgM4frUOslFjhVjRhbGaCNPtz/S8M6y46/fFKVuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-rest-pipeline": "^1.22.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-process": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@azure/core-process/-/core-process-1.0.0.tgz", + "integrity": "sha512-/shnJ+ooO8WPxDhPEeI/2oRQuubn16gZ6CvlbpWbEswZfzwI9tI/sMAHmF3x1LuQ9yZYXfLW3TjzGMLEC5blKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-rest-pipeline": { + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@azure/core-rest-pipeline/-/core-rest-pipeline-1.25.0.tgz", + "integrity": "sha512-bMs8ekJLjX8wPV+9IPBges1SLPyuDtE9g5gLDWOpxzKcoOFQnpLGkbcT1tdw3FaAmDS1gnPmMmJ6y/T5B96kIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@azure/core-auth": "^1.10.0", + "@azure/core-tracing": "^1.3.0", + "@azure/core-util": "^1.13.0", + "@azure/logger": "^1.3.0", + "@typespec/ts-http-runtime": "^0.3.4", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-tracing": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/core-tracing/-/core-tracing-1.4.0.tgz", + "integrity": "sha512-eGwxD0AtncrxeBM4tG8R55Pc3rdX1hNW2WibJAgYpCVA6E93mvvVH+LcssoVjOBrSKWS55yEIHsk0X8ctHmfOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/core-util": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@azure/core-util/-/core-util-1.14.0.tgz", + "integrity": "sha512-9n2pWK61veAuN0V20t9lOuoV4CFMdyAZ1ygZzvBGk/pBBJRib/PjL9PLXa/aI2CcPpyHfqVsxxqLCYl6uZlfDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.1.2", + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/identity": { + "version": "4.14.0", + "resolved": "https://registry.npmjs.org/@azure/identity/-/identity-4.14.0.tgz", + "integrity": "sha512-8utCLdTZn14CiAe0HW4JbtzUMsc0mdDwnjUvStFMrR4IxQP8S2eL9zVAdplpfORVJGYmidZElpeXRYjJQ4UyUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/abort-controller": "^2.0.0", + "@azure/core-auth": "^1.9.0", + "@azure/core-client": "^1.9.2", + "@azure/core-process": "^1.0.0", + "@azure/core-rest-pipeline": "^1.17.0", + "@azure/core-tracing": "^1.0.0", + "@azure/core-util": "^1.11.0", + "@azure/logger": "^1.0.0", + "@azure/msal-browser": "^5.5.0", + "@azure/msal-node": "^6.0.0", + "open": "^11.0.0", + "tslib": "^2.2.0" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/logger": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@azure/logger/-/logger-1.4.0.tgz", + "integrity": "sha512-rbAE25KUfjU/s3XHUdJgceoCP5dEOpMx85J04kF+QMdta73XkuG9JGHHinch+XIoKpBdqljin+KqURpJriSzLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typespec/ts-http-runtime": "^0.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@azure/msal-browser": { + "version": "5.26.0", + "resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-5.26.0.tgz", + "integrity": "sha512-GYKRquzDZmZggCdStWy2bNJKnPui1upssSuznJgP+/h6Mb0ldkUkaGvaY6uSGGmZOm0CGiBQ3b5BiGy43BpXSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.14.3" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-common": { + "version": "16.14.3", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.14.3.tgz", + "integrity": "sha512-tz3GvMrR9V/plb2lDdW8qaO8CPpfZevdExBKjltzzbAtyhK0eB2UIvji1aU+gkyHj3fxQ2ie+LNHyMXdmo8wOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@azure/msal-node": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@azure/msal-node/-/msal-node-6.0.1.tgz", + "integrity": "sha512-ixSO1Y/kCVRthRs+hSx/5qkwaunX1/RAePhlMN0wIpIQ4WEZ6AREGGnGd1AP0qspHVsAwzWQKGubpjh50JyJIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/msal-common": "16.14.1", + "jsonwebtoken": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/@azure/msal-node/node_modules/@azure/msal-common": { + "version": "16.14.1", + "resolved": "https://registry.npmjs.org/@azure/msal-common/-/msal-common-16.14.1.tgz", + "integrity": "sha512-Or6xhPNyi4zHW25158yxBoyxuCqNSPa5YBVqfF1J5Ks4MJWBo/USXdp05DQIPu1Zli00YZu6t0+h6KvHJealxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.2.tgz", + "integrity": "sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.3.tgz", + "integrity": "sha512-iex20d8CHVkyvg6B7UKV7uHnI2Bqo9g+EFfT9E0y+GvTvhZ/DwONJ+9aKb1dlqm0ZiGsL5RXjp0fCoJYnkeDjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.2", + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.6.tgz", + "integrity": "sha512-iiPQ3iRWwnJkeEn6RIu6SJPr7hYrLz6XZ9s/QZl+2/LI5KQVjpl2fdmDSZKuD4xP6GMmMPgHFFXg6k1Wkz0Trg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.2", + "@csstools/css-calc": "^3.4.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.2", + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.2.tgz", + "integrity": "sha512-40cSKyMvK+tq4qz6Awrlye2WGuOKt3FwPgtGg6KTfbHOWNw+Rk1rzbAtZnZ6IBhsY491HLRnDXwoyBAijmmILA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.2" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.15.tgz", + "integrity": "sha512-J0u7HkVl2nzSlhsiTOp4AmwcUQ3D+mGEEKfBy/7To5/y7F2OHwyLrXfrhR0SMgr4p5Lo+eaMVSeai24zUcBIxA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.2.tgz", + "integrity": "sha512-OoKoR0f76dCY666JlcbhmVTs2drYj1GUXZTYTcbUgJjh9Nv41aFfZ21bPQTERm5+L5cBDo466NltB2lplS5GBw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.16.0.tgz", + "integrity": "sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@secretlint/config-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-creator/-/config-creator-10.2.2.tgz", + "integrity": "sha512-BynOBe7Hn3LJjb3CqCHZjeNB09s/vgf0baBaHVw67w7gHF0d25c3ZsZ5+vv8TgwSchRdUCRrbbcq5i2B1fJ2QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/config-loader": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/config-loader/-/config-loader-10.2.2.tgz", + "integrity": "sha512-ndjjQNgLg4DIcMJp4iaRD6xb9ijWQZVbd9694Ol2IszBIbGPPkwZHzJYKICbTBmh6AH/pLr0CiCaWdGJU7RbpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "ajv": "^8.17.1", + "debug": "^4.4.1", + "rc-config-loader": "^4.1.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/core": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/core/-/core-10.2.2.tgz", + "integrity": "sha512-6rdwBwLP9+TO3rRjMVW1tX+lQeo5gBbxl1I5F8nh8bgGtKwdlCMhMKsBWzWg1ostxx/tIG7OjZI0/BxsP8bUgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/profiler": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "structured-source": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/formatter/-/formatter-10.2.2.tgz", + "integrity": "sha512-10f/eKV+8YdGKNQmoDUD1QnYL7TzhI2kzyx95vsJKbEa8akzLAR5ZrWIZ3LbcMmBLzxlSQMMccRmi05yDQ5YDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/resolver": "^10.2.2", + "@secretlint/types": "^10.2.2", + "@textlint/linter-formatter": "^15.2.0", + "@textlint/module-interop": "^15.2.0", + "@textlint/types": "^15.2.0", + "chalk": "^5.4.1", + "debug": "^4.4.1", + "pluralize": "^8.0.0", + "strip-ansi": "^7.1.0", + "table": "^6.9.0", + "terminal-link": "^4.0.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/formatter/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@secretlint/node": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/node/-/node-10.2.2.tgz", + "integrity": "sha512-eZGJQgcg/3WRBwX1bRnss7RmHHK/YlP/l7zOQsrjexYt6l+JJa5YhUmHbuGXS94yW0++3YkEJp0kQGYhiw1DMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-loader": "^10.2.2", + "@secretlint/core": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "@secretlint/source-creator": "^10.2.2", + "@secretlint/types": "^10.2.2", + "debug": "^4.4.1", + "p-map": "^7.0.3" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/profiler": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/profiler/-/profiler-10.2.2.tgz", + "integrity": "sha512-qm9rWfkh/o8OvzMIfY8a5bCmgIniSpltbVlUVl983zDG1bUuQNd1/5lUEeWx5o/WJ99bXxS7yNI4/KIXfHexig==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/resolver": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/resolver/-/resolver-10.2.2.tgz", + "integrity": "sha512-3md0cp12e+Ae5V+crPQYGd6aaO7ahw95s28OlULGyclyyUtf861UoRGS2prnUrKh7MZb23kdDOyGCYb9br5e4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@secretlint/secretlint-formatter-sarif": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-formatter-sarif/-/secretlint-formatter-sarif-10.2.2.tgz", + "integrity": "sha512-ojiF9TGRKJJw308DnYBucHxkpNovDNu1XvPh7IfUp0A12gzTtxuWDqdpuVezL7/IP8Ua7mp5/VkDMN9OLp1doQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-sarif-builder": "^3.2.0" + } + }, + "node_modules/@secretlint/secretlint-rule-no-dotenv": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-no-dotenv/-/secretlint-rule-no-dotenv-10.2.2.tgz", + "integrity": "sha512-KJRbIShA9DVc5Va3yArtJ6QDzGjg3PRa1uYp9As4RsyKtKSSZjI64jVca57FZ8gbuk4em0/0Jq+uy6485wxIdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/secretlint-rule-preset-recommend": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/secretlint-rule-preset-recommend/-/secretlint-rule-preset-recommend-10.2.2.tgz", + "integrity": "sha512-K3jPqjva8bQndDKJqctnGfwuAxU2n9XNCPtbXVI5JvC7FnQiNg/yWlQPbMUlBXtBoBGFYp08A94m6fvtc9v+zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/source-creator": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/source-creator/-/source-creator-10.2.2.tgz", + "integrity": "sha512-h6I87xJfwfUTgQ7irWq7UTdq/Bm1RuQ/fYhA3dtTIAop5BwSFmZyrchph4WcoEvbN460BWKmk4RYSvPElIIvxw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/types": "^10.2.2", + "istextorbinary": "^9.5.0" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@secretlint/types": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/@secretlint/types/-/types-10.2.2.tgz", + "integrity": "sha512-Nqc90v4lWCXyakD6xNyNACBJNJ0tNCwj2WNk/7ivyacYHxiITVgmLUFXTBOeCdy79iz6HtN9Y31uw/jbLrdOAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-2.3.0.tgz", + "integrity": "sha512-LtoMMhxAlorcGhmFYI+LhPgbPZCkgP6ra1YL604EeF6U98pLlQ3iWIGMdWSC+vWmPBWBNgmDBAhnAobLROJmwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@textlint/ast-node-types": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/ast-node-types/-/ast-node-types-15.8.0.tgz", + "integrity": "sha512-5CiH9COYmovWmExQgs7763DzX6Gy9zjkjJ7JxCC95wyTcjwQn/8poNF6fv3qzRlmx8CRRde8DHr9FcgAAiPzgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/linter-formatter/-/linter-formatter-15.8.0.tgz", + "integrity": "sha512-+oU3A235NATv6Lzi4xa4kJ65PuNJlIxesaO4AvDhDWA9FWm7y4XKWaoQCW1esgaQQ6dwnUiFKArQ8TcJ86mC4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azu/format-text": "^1.0.2", + "@azu/style-format": "^1.0.1", + "@textlint/module-interop": "15.8.0", + "@textlint/resolver": "15.8.0", + "@textlint/types": "15.8.0", + "debug": "^4.4.3", + "js-yaml": "^4.3.0", + "lodash": "^4.18.1", + "pluralize": "^2.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "table": "^6.9.0", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=20.18.0" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/linter-formatter/node_modules/pluralize": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-2.0.0.tgz", + "integrity": "sha512-TqNZzQCD4S42De9IfnnBvILN7HAW7riLqsCyp8lgjXeysyPlX5HhqKAcJHHHb9XskE4/a+7VGC9zzx8Ls0jOAw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/linter-formatter/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@textlint/module-interop": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/module-interop/-/module-interop-15.8.0.tgz", + "integrity": "sha512-rt+OR1WYGoLOY8HkA/aBPrqufF6yUUEsKEAh7XohTsT3lp9IyZFT6zOIbjul9P4FAzsmSPkcrYjVx3Bz/IUfkg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/resolver": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/resolver/-/resolver-15.8.0.tgz", + "integrity": "sha512-E88tzfX3K8Jykk+38aJ9cy8RquD8ABVOPTO2rFEESq0wcg8x6/ypdAS8ZgR7OKiGqlRF0hkO/m5PbQwVfKM3VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@textlint/types": { + "version": "15.8.0", + "resolved": "https://registry.npmjs.org/@textlint/types/-/types-15.8.0.tgz", + "integrity": "sha512-Anhc6y5736YIsvqae0U6k0YmB2M/QVHkEeOv2aydAn/WIkdI69dCOiDbe3/+RagS3qstFTSFWJzNRA2lUjv19w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@textlint/ast-node-types": "15.8.0" + } + }, + "node_modules/@types/jsdom": { + "version": "27.0.0", + "resolved": "https://registry.npmjs.org/@types/jsdom/-/jsdom-27.0.0.tgz", + "integrity": "sha512-NZyFl/PViwKzdEkQg96gtnB8wm+1ljhdDay9ahn4hgb+SfVtPCbm3TlmDUFXTA+MGN3CijicnMhG18SI5H3rFw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/tough-cookie": "*", + "parse5": "^7.0.0" + } + }, + "node_modules/@types/node": { + "version": "24.19.2", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.19.2.tgz", + "integrity": "sha512-93d49wCWJkCyN87MxLpNN6KXPCwFw7bVUg79mGUV1OS40JGWwVCr8n61DXCSqz7CV6/VfPkb7xec7uP2M+QHWQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz", + "integrity": "sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/sarif": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@types/sarif/-/sarif-2.1.7.tgz", + "integrity": "sha512-kRz0VEkJqWLf1LLVN4pT1cg1Z9wAuvI6L97V3m2f5B76Tg8d413ddvLBPTEHAZJlnn4XSvu0FkZtViCQGVyrXQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/tough-cookie": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/tough-cookie/-/tough-cookie-4.0.5.tgz", + "integrity": "sha512-/Ad8+nIOV7Rl++6f1BdKxFSMgmoqEoYbHRpPcx3JEfv8VRsQe9Z4mCXeJBzxs7mbHY/XOZZuXlRNfhpVPbs6ZA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/vscode": { + "version": "1.91.0", + "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.91.0.tgz", + "integrity": "sha512-PgPr+bUODjG3y+ozWUCyzttqR9EHny9sPAfJagddQjDwdtf66y2sDKJMnFZRuzBA2YtBGASqJGPil8VDUPvO6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typespec/ts-http-runtime": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@typespec/ts-http-runtime/-/ts-http-runtime-0.3.9.tgz", + "integrity": "sha512-edSdeAqkdxBVzA1yL1LrLCml1YjyCVvPMtMqJpbF+6K609tHe8V6sQUzFQSGcYNhcuhOceZtjvN32+mpIth30A==", + "dev": true, + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=22.0.0" + } + }, + "node_modules/@vscode/test-electron": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@vscode/test-electron/-/test-electron-3.1.0.tgz", + "integrity": "sha512-CRqv5u+YYoseuNVJ6Tyo4k0sF0mx4qnKMihRB0PjsUF8Dc0WKtCXo6CNL6nWWm5esfFQsQA/pejMj4ZbpJVLTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.5", + "jszip": "^3.10.1", + "ora": "^8.1.0", + "semver": "^7.6.2" + }, + "engines": { + "node": ">=22" + } + }, + "node_modules/@vscode/vsce": { + "version": "3.9.2", + "resolved": "https://registry.npmjs.org/@vscode/vsce/-/vsce-3.9.2.tgz", + "integrity": "sha512-XSxMosEEDO6vLxELAHVkwmhC0qe0ijZni2jB9Rcs8kQsW4lhTDQ/wMzmwFs/buotAWSnpmUp/dRWD2ufG3UYKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@azure/identity": "^4.1.0", + "@secretlint/node": "^10.1.2", + "@secretlint/secretlint-formatter-sarif": "^10.1.2", + "@secretlint/secretlint-rule-no-dotenv": "^10.1.2", + "@secretlint/secretlint-rule-preset-recommend": "^10.1.2", + "@vscode/vsce-sign": "^2.0.0", + "azure-devops-node-api": "^12.5.0", + "chalk": "^4.1.2", + "cheerio": "^1.0.0-rc.9", + "cockatiel": "^3.1.2", + "commander": "^12.1.0", + "form-data": "^4.0.0", + "glob": "^13.0.6", + "hosted-git-info": "^4.0.2", + "jsonc-parser": "^3.2.0", + "leven": "^3.1.0", + "markdown-it": "^14.1.0", + "mime": "^1.3.4", + "minimatch": "^10.2.2", + "parse-semver": "^1.1.1", + "read": "^1.0.7", + "secretlint": "^10.1.2", + "semver": "^7.5.2", + "tmp": "^0.2.3", + "typed-rest-client": "^1.8.4", + "url-join": "^4.0.1", + "xml2js": "^0.5.0", + "yauzl": "^3.2.1", + "yazl": "^2.2.2" + }, + "bin": { + "vsce": "vsce" + }, + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "keytar": "^7.7.0" + } + }, + "node_modules/@vscode/vsce-sign": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign/-/vsce-sign-2.1.0.tgz", + "integrity": "sha512-9AQrqazrBgTgRSuwleLVXUrIUphY02/SFCh2TKYoLV/xifJAdblhdmEmw5gUrYSPQ3sRwNs9iyCMD14sATEE6g==", + "dev": true, + "hasInstallScript": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optionalDependencies": { + "@vscode/vsce-sign-alpine-arm64": "2.0.6", + "@vscode/vsce-sign-alpine-x64": "2.0.6", + "@vscode/vsce-sign-darwin-arm64": "2.0.6", + "@vscode/vsce-sign-darwin-x64": "2.0.6", + "@vscode/vsce-sign-linux-arm": "2.0.6", + "@vscode/vsce-sign-linux-arm64": "2.0.6", + "@vscode/vsce-sign-linux-x64": "2.0.6", + "@vscode/vsce-sign-win32-arm64": "2.0.6", + "@vscode/vsce-sign-win32-x64": "2.0.6" + } + }, + "node_modules/@vscode/vsce-sign-alpine-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-arm64/-/vsce-sign-alpine-arm64-2.0.6.tgz", + "integrity": "sha512-wKkJBsvKF+f0GfsUuGT0tSW0kZL87QggEiqNqK6/8hvqsXvpx8OsTEc3mnE1kejkh5r+qUyQ7PtF8jZYN0mo8Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-alpine-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-alpine-x64/-/vsce-sign-alpine-x64-2.0.6.tgz", + "integrity": "sha512-YoAGlmdK39vKi9jA18i4ufBbd95OqGJxRvF3n6ZbCyziwy3O+JgOpIUPxv5tjeO6gQfx29qBivQ8ZZTUF2Ba0w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "alpine" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-arm64/-/vsce-sign-darwin-arm64-2.0.6.tgz", + "integrity": "sha512-5HMHaJRIQuozm/XQIiJiA0W9uhdblwwl2ZNDSSAeXGO9YhB9MH5C4KIHOmvyjUnKy4UCuiP43VKpIxW1VWP4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-darwin-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-darwin-x64/-/vsce-sign-darwin-x64-2.0.6.tgz", + "integrity": "sha512-25GsUbTAiNfHSuRItoQafXOIpxlYj+IXb4/qarrXu7kmbH94jlm5sdWSCKrrREs8+GsXF1b+l3OB7VJy5jsykw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm/-/vsce-sign-linux-arm-2.0.6.tgz", + "integrity": "sha512-UndEc2Xlq4HsuMPnwu7420uqceXjs4yb5W8E2/UkaHBB9OWCwMd3/bRe/1eLe3D8kPpxzcaeTyXiK3RdzS/1CA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-arm64/-/vsce-sign-linux-arm64-2.0.6.tgz", + "integrity": "sha512-cfb1qK7lygtMa4NUl2582nP7aliLYuDEVpAbXJMkDq1qE+olIw/es+C8j1LJwvcRq1I2yWGtSn3EkDp9Dq5FdA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-linux-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-linux-x64/-/vsce-sign-linux-x64-2.0.6.tgz", + "integrity": "sha512-/olerl1A4sOqdP+hjvJ1sbQjKN07Y3DVnxO4gnbn/ahtQvFrdhUi0G1VsZXDNjfqmXw57DmPi5ASnj/8PGZhAA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@vscode/vsce-sign-win32-arm64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-arm64/-/vsce-sign-win32-arm64-2.0.6.tgz", + "integrity": "sha512-ivM/MiGIY0PJNZBoGtlRBM/xDpwbdlCWomUWuLmIxbi1Cxe/1nooYrEQoaHD8ojVRgzdQEUzMsRbyF5cJJgYOg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@vscode/vsce-sign-win32-x64": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@vscode/vsce-sign-win32-x64/-/vsce-sign-win32-x64-2.0.6.tgz", + "integrity": "sha512-mgth9Kvze+u8CruYMmhHw6Zgy3GRX2S+Ed5oSokDEK5vPEwGGKnmuXua9tmFhomeAnhgJnL4DCna3TiNuGrBTQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "SEE LICENSE IN LICENSE.txt", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-7.3.0.tgz", + "integrity": "sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==", + "dev": true, + "license": "MIT", + "dependencies": { + "environment": "^1.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.4.0.tgz", + "integrity": "sha512-KzTVk2tCWAHtYrvvvaP8bJKJq2pVinhLcGEQdtLIYPbmNGNyYe8QwNaTUYQp2J7/vIsUKt5QCqAfUkYyG9DkOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/azure-devops-node-api": { + "version": "12.5.0", + "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-12.5.0.tgz", + "integrity": "sha512-R5eFskGvOm3U/GzeAuxRkUsAl0hrAwGgWn6zAd2KrZmrEhWZVqLew4OOupbQlXUuojUzpGtq62SmdhJ06N88og==", + "dev": true, + "license": "MIT", + "dependencies": { + "tunnel": "0.0.6", + "typed-rest-client": "^1.8.4" + } + }, + "node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/bidi-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz", + "integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/binaryextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/binaryextensions/-/binaryextensions-6.11.0.tgz", + "integrity": "sha512-sXnYK/Ij80TO3lcqZVV2YgfKN5QjUWIRk/XSm2J/4bd/lPko3lvk0O4ZppH6m+6hB2/GTu+ptNwVFe1xh+QLQw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", + "dev": true, + "license": "ISC" + }, + "node_modules/boundary": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/boundary/-/boundary-2.0.0.tgz", + "integrity": "sha512-rJKn5ooC9u8q13IMCrW0RSp31pxBCHE3y9V/tp3TdWSLf8Em3p6Di4NBpfzbJge9YjjFEsD0RtFEjtvHL5VyEA==", + "dev": true, + "license": "BSD-2-Clause" + }, + "node_modules/brace-expansion": { + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/bundle-name": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.1.tgz", + "integrity": "sha512-DdH81/zPLVS11EUgWq3tEu/xn+EzljlMYooDNdzWEnFha3R3NBMpMV1UqYIpjYHV/SgpFKMIX1Oh7o06SjM/oA==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cheerio": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-1.2.0.tgz", + "integrity": "sha512-WDrybc/gKFpTYQutKIK6UvfcuxijIZfMfXaYm8NMsPQxSYvf+13fXUJ4rztGGbJcBQ/GF55gvrZ0Bc0bj/mqvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cheerio-select": "^2.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "encoding-sniffer": "^0.2.1", + "htmlparser2": "^10.1.0", + "parse5": "^7.3.0", + "parse5-htmlparser2-tree-adapter": "^7.1.0", + "parse5-parser-stream": "^7.1.2", + "undici": "^7.19.0", + "whatwg-mimetype": "^4.0.0" + }, + "engines": { + "node": ">=20.18.1" + }, + "funding": { + "url": "https://github.com/cheeriojs/cheerio?sponsor=1" + } + }, + "node_modules/cheerio-select": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cheerio-select/-/cheerio-select-2.1.0.tgz", + "integrity": "sha512-9v9kG0LvzrlcungtnJtpGNxY+fzECQKhK4EGJX2vByejiMX84MFNQw4UxPJl3bFbTMw+Dfs37XaIkCwTZfLh4g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-select": "^5.1.0", + "css-what": "^6.1.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/cli-cursor": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-5.0.0.tgz", + "integrity": "sha512-aCj4O5wKyszjMmDT4tZj93kxyydN/K5zPWSCe6/0AV/AA1pqe5ZBIw0a2ZfPQV7lL5/yb5HsUreJ6UFAF1tEQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "restore-cursor": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-spinners": { + "version": "2.9.2", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.9.2.tgz", + "integrity": "sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cockatiel": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/cockatiel/-/cockatiel-3.2.1.tgz", + "integrity": "sha512-gfrHV6ZPkquExvMh9IOkKsBzNDk6sDuZ6DdBGUBkvFnTCqCxzpuq48RySgP0AnaqQkw2zynOFj9yly6T1Q2G5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=16" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/css-select": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.2.2.tgz", + "integrity": "sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/css-what": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.2.2.tgz", + "integrity": "sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssstyle": { + "version": "5.3.7", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-5.3.7.tgz", + "integrity": "sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^4.1.1", + "@csstools/css-syntax-patches-for-csstree": "^1.0.21", + "css-tree": "^3.1.0", + "lru-cache": "^11.2.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/cssstyle/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/data-urls": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-6.0.1.tgz", + "integrity": "sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^15.1.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/data-urls/node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/decompress-response": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^3.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/editions": { + "version": "6.22.0", + "resolved": "https://registry.npmjs.org/editions/-/editions-6.22.0.tgz", + "integrity": "sha512-UgGlf8IW75je7HZjNDpJdCv4cGJWIi6yumFdZ0R7A8/CIhQiWUjyGLCxdHpd8bmyD1gnkfUNK0oeOXqUS2cpfQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "version-range": "^4.15.0" + }, + "engines": { + "ecmascript": ">= es5", + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/encoding-sniffer": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/encoding-sniffer/-/encoding-sniffer-0.2.1.tgz", + "integrity": "sha512-5gvq20T6vfpekVtqrYQsSCFZ1wEg5+wW0/QaZMWkFr6BqD3NfKs0rLCx4rrVlSWJeZb5NBJgVLswK/w2MWU+Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "^0.6.3", + "whatwg-encoding": "^3.1.1" + }, + "funding": { + "url": "https://github.com/fb55/encoding-sniffer?sponsor=1" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/environment": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/environment/-/environment-1.1.0.tgz", + "integrity": "sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-uri": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.9.tgz", + "integrity": "sha512-hS/0Wt3Ya043oKXs0sIxrMpKQITXhMLIrVAKKXi4gozGC9v7YRWVnXIZzjNPTO02M9BdxLCWqK1yRXgNziVyJQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fastq": { + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.3.tgz", + "integrity": "sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/form-data": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", + "integrity": "sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.4", + "mime-types": "^2.1.35" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/fs-extra": { + "version": "11.4.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.1.tgz", + "integrity": "sha512-KYAb4c9BJQI6QqGKthV68OHe0badztdXJWKo0WtBA9IuCFPTKvE5ZdUBglP833aMjhaSPNO4A5j/EkzZtGlKjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-east-asian-width": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.7.0.tgz", + "integrity": "sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/globby": { + "version": "14.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-14.1.0.tgz", + "integrity": "sha512-0Ia46fDOaT7k4og1PDW4YbodWWr3scS2vAr2lTbsplOt2WkKp0vQbkI9wKis/T5LV/dqPjO3bpS/z6GTJB82LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^2.1.0", + "fast-glob": "^3.3.3", + "ignore": "^7.0.3", + "path-type": "^6.0.0", + "slash": "^5.1.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/htmlparser2": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.1.0.tgz", + "integrity": "sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.2", + "entities": "^7.0.1" + } + }, + "node_modules/htmlparser2/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true + }, + "node_modules/ignore": { + "version": "7.0.14", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.14.tgz", + "integrity": "sha512-wCBiZ77u1tuWde6G/nfOtLaCTYcFDU5yCzARzK10y+rLhzYoL7a7yEemcopcc2Mzow7gZOIjnV2ym1NYmdiJOQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/immediate": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-2.0.0.tgz", + "integrity": "sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/istextorbinary": { + "version": "9.5.0", + "resolved": "https://registry.npmjs.org/istextorbinary/-/istextorbinary-9.5.0.tgz", + "integrity": "sha512-5mbUj3SiZXCuRf9fT3ibzbSSEWiy63gFfksmGfdOzujPjW3k+z8WvIBxcJHBoQNlaZaiyB25deviif2+osLmLw==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "binaryextensions": "^6.11.0", + "editions": "^6.21.0", + "textextensions": "^6.11.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.2.tgz", + "integrity": "sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "27.4.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-27.4.0.tgz", + "integrity": "sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@acemir/cssom": "^0.9.28", + "@asamuzakjp/dom-selector": "^6.7.6", + "@exodus/bytes": "^1.6.0", + "cssstyle": "^5.3.4", + "data-urls": "^6.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "parse5": "^8.0.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.0", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^15.1.0", + "ws": "^8.18.3", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/entities": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", + "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/jsdom/node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.3.1.tgz", + "integrity": "sha512-HUgH65KyejrUFPvHFPbqOY0rsFip3Bo5wb4ngvdi1EpCYWUQDC5V+Y7mZws+DLkr4M//zQJoanu1SP+87Dv1oQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonwebtoken": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.3.tgz", + "integrity": "sha512-MT/xP0CrubFRNLNKvxJ2BYfy53Zkm++5bX9dtuPbqAeQpTVe0MQTFhao8+Cp//EmJp244xt6Drw/GVEGCUj40g==", + "dev": true, + "license": "MIT", + "dependencies": { + "jws": "^4.0.1", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/jszip": { + "version": "3.10.2", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.2.tgz", + "integrity": "sha512-3l+rb15IOWtUhU0H5MFqES/T6Kh7abYwjosBey/vD6hDt8zoEffkSC5Ws5SGtgVw3gBx2NEbhTeSW1+kWkpyTQ==", + "dev": true, + "license": "(MIT OR GPL-3.0-or-later)", + "dependencies": { + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" + } + }, + "node_modules/jwa": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", + "integrity": "sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-equal-constant-time": "^1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jws/-/jws-4.0.1.tgz", + "integrity": "sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==", + "dev": true, + "license": "MIT", + "dependencies": { + "jwa": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/keytar": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz", + "integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "node-addon-api": "^4.3.0", + "prebuild-install": "^7.0.1" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/lie": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "immediate": "~3.0.5" + } + }, + "node_modules/linkify-it": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-5.0.2.tgz", + "integrity": "sha512-ONTm2jCMAVZjgQa/Fy1kScXsuOoF5NPTsoFBdE1KVIZ2vAh/r9+Bqo+0jINCBYnavTPQZz38QzFTme79ENoN3Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "uc.micro": "^2.0.0" + } + }, + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.truncate": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz", + "integrity": "sha512-jttmRe7bRse52OsWIMDLaXxWqRAmtIUccAQ3garviCqJjafXOfNMO0yMfNpdD6zbGaTU0P5Nz7e7gAT6cKmJRw==", + "dev": true, + "license": "MIT" + }, + "node_modules/log-symbols": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", + "integrity": "sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "is-unicode-supported": "^1.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/is-unicode-supported": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-1.3.0.tgz", + "integrity": "sha512-43r2mRvz+8JRIKnWJ+3j8JtjRKZ6GmjzfaE/qiBJnikNnYv/6bagRJ1kUhNk8R5EX/GkobD+r+sfxCPJsiKBLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/markdown-it": { + "version": "14.3.3", + "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-14.3.3.tgz", + "integrity": "sha512-L//tDAkjTjJCU6pBUSBTgs3Kg4InVaZuUZog/b6V12UKhcDQ7S78877ibbCanRExwPuYP1CZD7Gd2dxSy1GXRg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/markdown-it" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1", + "entities": "^4.5.0", + "linkify-it": "^5.0.2", + "mdurl": "^2.0.0", + "punycode.js": "^2.3.1", + "uc.micro": "^2.1.0" + }, + "bin": { + "markdown-it": "bin/markdown-it.mjs" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/mdurl": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-2.1.0.tgz", + "integrity": "sha512-1+HBaOx0zi/dQWht8rNv9MYf9qqpqL/kxI0hXImU6Y547zM6Sni8BQibt7ifgMcYtQg41ao3Ivd6cnSM86inpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true, + "license": "MIT", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-function": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/mimic-function/-/mimic-function-5.0.1.tgz", + "integrity": "sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/mimic-response": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/minimatch": { + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.8" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "dev": true, + "license": "MIT", + "optional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mute-stream": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", + "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", + "dev": true, + "license": "ISC" + }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-abi": { + "version": "3.101.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.101.0.tgz", + "integrity": "sha512-bkb/RkuWCE64eWu1PCh3Fu2pGc9mKRs+kOE+FU2bGHRYlQa86/D321DSATV54AsCQMKz3/xSt9sRgraZTpqdhQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/node-addon-api": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz", + "integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/node-sarif-builder": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/node-sarif-builder/-/node-sarif-builder-3.4.0.tgz", + "integrity": "sha512-tGnJW6OKRii9u/b2WiUViTJS+h7Apxx17qsMUjsUeNDiMMX5ZFf8F8Fcz7PAQ6omvOxHZtvDTmOYKJQwmfpjeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/sarif": "^2.1.7", + "fs-extra": "^11.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.2.tgz", + "integrity": "sha512-V6gygoYb/5EmNI+MEGrWkC+e6+Rr7mTmfHrxDbLzxQogBkgzo76rkok0Am6thgSF7Mv2nLOajAJj5vDJZEFn7g==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.2.tgz", + "integrity": "sha512-puUZAUKT5m8Zzvs72XWy3HtvVbTWljRE66cP60bxJzAqf2DgICo7lYTY2IHUmLnNpjYvw5bvmoHvPc0QO2a62w==", + "dev": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data/node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-inspect": { + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-7.0.0.tgz", + "integrity": "sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "mimic-function": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.4.tgz", + "integrity": "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.5.1", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.2.1", + "wsl-utils": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-8.2.0.tgz", + "integrity": "sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.3.0", + "cli-cursor": "^5.0.0", + "cli-spinners": "^2.9.2", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.0.0", + "log-symbols": "^6.0.0", + "stdin-discarder": "^0.2.2", + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, + "license": "MIT" + }, + "node_modules/ora/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.1.1.tgz", + "integrity": "sha512-6Lh3jQPLthYujSrlw6ccWXBGZTkoTCz27Hd92g79LH/kjAbgoEu0t442cCCNbegPSJsA0lwDX8z0bcKtkpA32g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-semver": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/parse-semver/-/parse-semver-1.1.1.tgz", + "integrity": "sha512-Eg1OuNntBMH0ojvEKSrvDSnwLmvVuUOSdylH/pSCPNMIspLlweJyIWXCE+k/5hm3cj/EBUYwmWkjhBALNP4LXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^5.1.0" + } + }, + "node_modules/parse-semver/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/parse5": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.3.0.tgz", + "integrity": "sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^6.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-htmlparser2-tree-adapter": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-7.1.0.tgz", + "integrity": "sha512-ruw5xyKs6lrpo9x9rCZqZZnIUntICjQAd0Wsmp396Ul9lN/h+ifgVV1x1gZHi8euej6wTfpqX8j+BFQxF0NS/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "domhandler": "^5.0.3", + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-parser-stream": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5-parser-stream/-/parse5-parser-stream-7.1.2.tgz", + "integrity": "sha512-JyeQc9iwFLn5TbvvqACIF/VXG6abODeB3Fwmv/TGdLk2LfbWkaySGY72at4+Ty7EkPZj854u4CrICqNk2qIbow==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/path-scurry": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.2.tgz", + "integrity": "sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-type": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-6.0.0.tgz", + "integrity": "sha512-Vj7sf++t5pBD637NSfkxpHSMfWaeig5+DKWLhcqIYx6mWQz5hdJTGDVMQiJcw1ZYkhs7AazKDGpRVji1LJCZUQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/powershell-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.1.tgz", + "integrity": "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/punycode.js": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode.js/-/punycode.js-2.3.1.tgz", + "integrity": "sha512-uxFIHU0YlHYhDQtV4R9J6a52SLx28BCjT+4ieh7IGbgwVJWO+km431c4yRlREUAsAmt/uMjQUyQHNEPf0M39CA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.17.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.17.0.tgz", + "integrity": "sha512-5LK5BZ2XDHMvcUJaf0CQ5HL3aVgKbpklvByC7qLSxYkfE8COEEbJg5xCHWCTqzqi0Gs4Jn5Mv5v3R38W6edscA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc-config-loader": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/rc-config-loader/-/rc-config-loader-4.1.4.tgz", + "integrity": "sha512-3GiwEzklkbXTDp52UR5nT8iXgYAx1V9ZG/kDZT7p60u2GCv2XTwQq4NzinMoMpNtXhmt3WkhYXcj6HH8HdwCEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "js-yaml": "^4.1.1", + "json5": "^2.2.3", + "require-from-string": "^2.0.2" + } + }, + "node_modules/read": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", + "integrity": "sha512-rSOKNYUmaxy0om1BNjMN4ezNT6VKK+2xF4GBhc81mkH7L60i6dp8qPYrkndNLT3QPphoII3maL9PVC9XmhHwVQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~0.0.4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/read-pkg": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-9.0.1.tgz", + "integrity": "sha512-9viLL4/n1BJUCT1NXVTdS1jtm80yDEgR5T4yCelII49Mbj0v1rZdKqj7zCiYdbB0CuCgdrvHcNogAKTFPBocFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/normalize-package-data": "^2.4.3", + "normalize-package-data": "^6.0.0", + "parse-json": "^8.0.0", + "type-fest": "^4.6.0", + "unicorn-magic": "^0.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg/node_modules/unicorn-magic": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.1.0.tgz", + "integrity": "sha512-lRfVq8fE8gz6QMBuDM6a+LO3IAzTi05H6gCVaUpir2E1Rwpo4ZUog45KpNXKC/Mn3Yb9UDuHumeFTo9iV/D9FQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/restore-cursor": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-5.1.0.tgz", + "integrity": "sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "onetime": "^7.0.0", + "signal-exit": "^4.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/sax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.1.tgz", + "integrity": "sha512-42tBVwLWnaQvW5zc4HbZrTuWccECCZfBi92FDuwtqxasH+JbPB3/FOKb1m222K42R4WxuxzzMsTswfzgtSu64Q==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/secretlint": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/secretlint/-/secretlint-10.2.2.tgz", + "integrity": "sha512-xVpkeHV/aoWe4vP4TansF622nBEImzCY73y/0042DuJ29iKIaqgoJ8fGxre3rVSHHbxar4FdJobmTnLp9AU0eg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@secretlint/config-creator": "^10.2.2", + "@secretlint/formatter": "^10.2.2", + "@secretlint/node": "^10.2.2", + "@secretlint/profiler": "^10.2.2", + "debug": "^4.4.1", + "globby": "^14.1.0", + "read-pkg": "^9.0.1" + }, + "bin": { + "secretlint": "bin/secretlint.js" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^6.0.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/slash": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-5.1.0.tgz", + "integrity": "sha512-ZA6oR3T/pEyuqwMgAKT0/hAv8oAXckzbkmR0UkUosQ+Mc4RxGoJkRmwHgHufaenlyAgE1Mxgpdcrf75y6XcnDg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/source-map-js": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.2.tgz", + "integrity": "sha512-KGj/8Y43x35aZVDtt+J4mK1hoLGHULMYfSkODJNQjNDC3oW1PqPoxMwo0pLUsWM/UEGzON/NxeHywEfNXNP3Vw==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", + "dev": true, + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.24", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.24.tgz", + "integrity": "sha512-cLS9TtWkIQFyLkJ3/5aFQAOHOSKTlOs/7WDut/XPSdjom1fJhUdkepeJAKXa9Y05+FabHd0sti+Et559vDtkpQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/stdin-discarder": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", + "integrity": "sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/structured-source": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/structured-source/-/structured-source-4.0.0.tgz", + "integrity": "sha512-qGzRFNJDjFieQkl/sVOI2dUjHKRyL9dAJi2gCPGJLbJHBIkyOHxjuocpIEfbLioX+qSJpvbYdT49/YCdMznKxA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "boundary": "^2.0.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-hyperlinks": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-3.2.0.tgz", + "integrity": "sha512-zFObLMyZeEwzAoKCyu1B91U79K2t7ApXuQfo8OuxwXLDgcKxuwM+YvcbIhm6QWqz7mHUH1TVytR1PwVVjEuMig==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0", + "supports-color": "^7.0.0" + }, + "engines": { + "node": ">=14.18" + }, + "funding": { + "url": "https://github.com/chalk/supports-hyperlinks?sponsor=1" + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/table": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/table/-/table-6.9.0.tgz", + "integrity": "sha512-9kY+CygyYM6j02t5YFHbNz2FN5QmYGv9zAjVp4lCDjlCw7amdckXlEt/bjMhUIfj4ThGRE4gCUH5+yGnNuPo5A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "ajv": "^8.0.1", + "lodash.truncate": "^4.4.2", + "slice-ansi": "^4.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/table/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/table/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar-fs": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.5.tgz", + "integrity": "sha512-OboTd8mmMhZDNPV+UjQcK9yKAatXu2aJ+r1w4im1Otd4M4fl2hwvdoXUxIYHFTHWK/3y3FarBP70v3vwmGlOxw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/terminal-link": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/terminal-link/-/terminal-link-4.0.0.tgz", + "integrity": "sha512-lk+vH+MccxNqgVqSnkMVKx4VLJfnLjDBGzH16JVZjKE2DoxP57s6/vt6JmXV5I3jBcfGrxNrYtC+mPtU7WJztA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-escapes": "^7.0.0", + "supports-hyperlinks": "^3.2.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true, + "license": "MIT" + }, + "node_modules/textextensions": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/textextensions/-/textextensions-6.11.0.tgz", + "integrity": "sha512-tXJwSr9355kFJI3lbCkPpUH5cP8/M0GGy2xLO34aZCjMXBaK3SoPnZwr/oWmo1FdCnELcs4npdCIOFtq9W3ruQ==", + "dev": true, + "license": "Artistic-2.0", + "dependencies": { + "editions": "^6.21.0" + }, + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/tldts": { + "version": "7.4.19", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.19.tgz", + "integrity": "sha512-48dH6aSpQnpbzDUc4vIQZ1VjB8tkK+e8c1yx05/SZK+rkssgjEOlxDd/yU8/a4vGYQ9vRgJr9dwMq9TJ0b3X2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.19" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.19", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.19.tgz", + "integrity": "sha512-goNXV6Ho9TIOfpJZanTd6CKG5DyYgYAL+k+22T0SLh8l6+KHIfBUPFuePuSZv05UttIaaLmI9tb7TmGIdK5AkQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tmp": { + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.14" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "dev": true, + "license": "0BSD" + }, + "node_modules/tunnel": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz", + "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6.11 <=0.7.0 || >=0.7.3" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-rest-client": { + "version": "1.8.11", + "resolved": "https://registry.npmjs.org/typed-rest-client/-/typed-rest-client-1.8.11.tgz", + "integrity": "sha512-5UvfMpd1oelmUPRbbaVnq+rHP7ng2cE4qoQkQeAqxRL6PklkxsM0g32/HL0yfvruK6ojQ5x8EE+HF4YV6DtuCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "qs": "^6.9.1", + "tunnel": "0.0.6", + "underscore": "^1.12.1" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/uc.micro": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/uc.micro/-/uc.micro-2.1.0.tgz", + "integrity": "sha512-ARDJmphmdvUk6Glw7y9DQ2bFkKBHwQHLi2lsaH6PPmz/Ka9sFOBsBluozhDltWmnv9u/cF6Rt87znRTPV+yp/A==", + "dev": true, + "license": "MIT" + }, + "node_modules/underscore": { + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici": { + "version": "7.30.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.30.1.tgz", + "integrity": "sha512-03KrMbjIFDWQR5RNPrSw3bd1r12JpyFQl9/yxjUbJtqkjmllqC5lFjZh6ujeuJCKr8EOQvRW872Oy/az+nLYxg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/url-join": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/url-join/-/url-join-4.0.1.tgz", + "integrity": "sha512-jk1+QP6ZJqyOiuEI9AEWQfju/nB2Pw466kbA0LEZljHwKeMgd9WrAEgEGxjPDD2+TNbbb37rTyhEfrCXfuKXnA==", + "dev": true, + "license": "MIT" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/version-range": { + "version": "4.15.0", + "resolved": "https://registry.npmjs.org/version-range/-/version-range-4.15.0.tgz", + "integrity": "sha512-Ck0EJbAGxHwprkzFO966t4/5QkRuzh+/I1RxhLgUKKwEn+Cd8NwM60mE3AqBZg5gYODoXW0EFsQvbZjRlvdqbg==", + "dev": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=4" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "deprecated": "Use @exodus/bytes instead for a more spec-conformant and faster implementation", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "15.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-15.1.0.tgz", + "integrity": "sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC", + "optional": true + }, + "node_modules/ws": { + "version": "8.22.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.22.0.tgz", + "integrity": "sha512-Ydggc987+RO0AnWtZ/7Wq9FtNvcrL1b/RO0ud9mWjUPgDrsAAwQSF51sm2hm1XofbU/4jkpGEsLFsZZxU+1DOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.1.tgz", + "integrity": "sha512-c16PKLIRxBYpR3jSWsdS7SFp0COm5SOQdiFjY818dYFHJbMGuLBszpF07LBWmOS1uzrHa9VGdynsEgoeKy0oOQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.2.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xml2js": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.5.0.tgz", + "integrity": "sha512-drPFnkQJik/O+uPKpqSgr22mpuFHqKdbS835iAQrUC73L2F5WkboIRd63ai/2Yg6I1jzifPFKH2NTK+cfglkIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true, + "license": "ISC" + }, + "node_modules/yauzl": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-3.4.0.tgz", + "integrity": "sha512-jIH9yLR9wqr0wOS0TpBvo/g/2UgZH5qePVbjgRliiF0BYvOZyaBknKsF+x9Iht0O6sqgnB93rCICdOZFecJuDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "pend": "~1.2.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yazl": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/yazl/-/yazl-2.5.1.tgz", + "integrity": "sha512-phENi2PLiHnHb6QBVot+dJnaAZ0xosj7p3fWl+znIjBDlnMI2PsZCJZ306BPTFOaHf5qdDEI8x5qFrSOBN5vrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-crc32": "~0.2.3" + } + } + } +} diff --git a/vscode/package.json b/vscode/package.json new file mode 100644 index 0000000..b7ef3aa --- /dev/null +++ b/vscode/package.json @@ -0,0 +1,301 @@ +{ + "name": "mcpp-vscode", + "displayName": "%displayName%", + "description": "%description%", + "version": "1.0.0", + "publisher": "mcpp-community", + "license": "Apache-2.0", + "icon": "media/logo.png", + "repository": { + "type": "git", + "url": "https://github.com/mcpp-community/mcpp-ide.git" + }, + "homepage": "https://github.com/mcpp-community/mcpp-ide#readme", + "bugs": { + "url": "https://github.com/mcpp-community/mcpp-ide/issues" + }, + "engines": { + "vscode": "^1.91.0" + }, + "extensionPack": [ + "sunrisepeak.mcpp-language-server" + ], + "categories": [ + "Programming Languages", + "Debuggers", + "Testing", + "Other" + ], + "keywords": [ + "mcpp", + "C++", + "C++23", + "modules", + "build" + ], + "activationEvents": [ + "workspaceContains:**/mcpp.toml", + "onLanguage:mcpp-toml", + "onDebugResolve:mcpp", + "onDebugDynamicConfigurations:mcpp" + ], + "main": "./out/src/extension.js", + "capabilities": { + "untrustedWorkspaces": { + "supported": "limited", + "description": "%untrustedWorkspaces.description%", + "restrictedConfigurations": [ + "mcpp.path", + "mcpp.ide.backendPath" + ] + } + }, + "contributes": { + "languages": [ + { + "id": "cpp", + "filenames": [ + "build.mcpp" + ] + }, + { + "id": "mcpp-toml", + "aliases": [ + "mcpp TOML", + "mcpp.toml" + ], + "filenames": [ + "mcpp.toml" + ] + } + ], + "grammars": [ + { + "language": "mcpp-toml", + "scopeName": "source.toml.mcpp", + "path": "./syntaxes/mcpp-toml.tmLanguage.json" + }, + { + "scopeName": "source.cpp.mcpp-modules", + "injectTo": [ + "source.cpp" + ], + "path": "./syntaxes/mcpp-modules.tmLanguage.json" + } + ], + "viewsContainers": { + "activitybar": [ + { + "id": "mcpp", + "title": "%viewsContainer.mcpp.title%", + "icon": "media/activity-bar.png" + } + ] + }, + "views": { + "mcpp": [ + { + "id": "mcpp.project", + "name": "%view.mcpp.project.name%", + "contextualTitle": "%view.mcpp.project.name%", + "when": "!mcpp.sidebarHidden && mcpp.views.project" + }, + { + "id": "mcpp.library", + "name": "%view.mcpp.library.name%", + "contextualTitle": "%view.mcpp.library.name%", + "description": "%view.mcpp.library.description%", + "type": "webview", + "when": "!mcpp.sidebarHidden && mcpp.views.library", + "initialSize": 40 + }, + { + "id": "mcpp.cache", + "name": "%view.mcpp.cache.name%", + "contextualTitle": "%view.mcpp.cache.name%", + "description": "%view.mcpp.cache.description%", + "type": "webview", + "visibility": "collapsed", + "when": "!mcpp.sidebarHidden && mcpp.views.cache" + } + ] + }, + "taskDefinitions": [ + { + "type": "mcpp", + "required": [ + "command" + ], + "properties": { + "command": { + "type": "string", + "enum": [ + "build", + "test", + "run", + "clean" + ], + "description": "%taskDefinition.mcpp.command%" + }, + "target": { + "type": "string", + "description": "%taskDefinition.mcpp.target%" + }, + "profile": { + "type": "string", + "enum": [ + "dev", + "release" + ], + "description": "%taskDefinition.mcpp.profile%" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "%taskDefinition.mcpp.args%" + }, + "root": { + "type": "string", + "description": "%taskDefinition.mcpp.root%" + } + } + } + ], + "debuggers": [ + { + "type": "mcpp", + "label": "%debugger.mcpp.label%", + "languages": [ + "cpp", + "c" + ], + "configurationAttributes": { + "launch": { + "properties": { + "target": { + "type": "string", + "description": "%debug.mcpp.target%" + }, + "profile": { + "type": "string", + "enum": [ + "dev", + "release" + ], + "description": "%debug.mcpp.profile%" + }, + "engine": { + "type": "string", + "enum": [ + "auto", + "cppdbg", + "lldb", + "lldb-dap", + "gdb" + ], + "description": "%debug.mcpp.engine%" + }, + "args": { + "type": "array", + "items": { + "type": "string" + }, + "description": "%debug.mcpp.args%" + } + } + } + }, + "initialConfigurations": [ + { + "type": "mcpp", + "request": "launch", + "name": "mcpp: debug" + } + ], + "configurationSnippets": [ + { + "label": "mcpp: debug", + "body": { + "type": "mcpp", + "request": "launch", + "name": "mcpp: debug" + } + } + ] + } + ], + "colors": [ + { + "id": "mcpp.cacheOkForeground", + "description": "%colors.mcpp.cacheOkForeground%", + "defaults": { + "dark": "#89d185", + "light": "#388a34", + "highContrast": "#00ff00" + } + }, + { + "id": "mcpp.cacheStaleForeground", + "description": "%colors.mcpp.cacheStaleForeground%", + "defaults": { + "dark": "#e2c08d", + "light": "#bf8803", + "highContrast": "#ffff00" + } + } + ], + "configurationDefaults": { + "files.associations": { + "*.ccm": "cpp", + "*.cppm": "cpp", + "*.ixx": "cpp", + "*.mpp": "cpp" + } + }, + "menus": { + "view/item/context": [ + { + "command": "mcpp.test", + "when": "view == mcpp.project && viewItem == mcppTest", + "group": "inline@1" + }, + { + "command": "mcpp.run", + "when": "view == mcpp.project && viewItem == mcppExecutable", + "group": "inline@1" + } + ], + "view/title": [ + { + "command": "mcpp.build", + "when": "view == mcpp.project", + "group": "navigation@1" + }, + { + "command": "mcpp.selectTarget", + "when": "view == mcpp.project", + "group": "navigation@3" + } + ] + } + }, + "scripts": { + "compile": "tsc -p tsconfig.json", + "gen": "cd .. && mcpp run mcpp-ide-dev -- gen vscode --out vscode/dist/extension --stage", + "test": "npm run compile && node --test \"out/test/unit/**/*.test.js\" && node --test \"../webui/tests/*.test.js\"", + "test:e2e": "npm run compile && npm run gen && node out/test/e2e/runTest.js", + "package": "npm run compile && npm run gen && cd dist/extension && vsce package --no-dependencies -o ../mcpp-vscode-$npm_package_version.vsix", + "check:webui": "tsc -p ../webui/tsconfig.json" + }, + "devDependencies": { + "@types/node": "^24.0.0", + "@types/vscode": "~1.91.0", + "@vscode/test-electron": "^3.1.0", + "@vscode/vsce": "^3.9.2", + "jsdom": "^27.0.0", + "@types/jsdom": "^27.0.0", + "typescript": "^5.9.0" + } +} diff --git a/vscode/src/backend/client.ts b/vscode/src/backend/client.ts new file mode 100644 index 0000000..daec36f --- /dev/null +++ b/vscode/src/backend/client.ts @@ -0,0 +1,164 @@ +// The backend's wire, as the adapter speaks it: `mcpp-ide serve` started as a child process, +// JSON-RPC 2.0 framed as the LSP base protocol on its standard streams. No editor API here, so the +// unit tests and the panel tests drive a real backend through the same code. +import { spawn, type ChildProcess } from "node:child_process"; +import { EventEmitter } from "node:events"; + +export interface RpcError { + code: number; + message: string; + data?: unknown; +} + +export class BackendError extends Error { + constructor(public readonly method: string, public readonly error: RpcError) { + super(error.message); + } +} + +type Pending = { resolve: (v: unknown) => void; reject: (e: unknown) => void; method: string }; + +/** Splits a byte stream into the bodies of Content-Length frames. */ +export class FrameReader { + private buffer = Buffer.alloc(0); + + feed(chunk: Buffer): string[] { + this.buffer = Buffer.concat([this.buffer, chunk]); + const out: string[] = []; + for (;;) { + const headerEnd = this.buffer.indexOf("\r\n\r\n"); + if (headerEnd < 0) break; + const headers = this.buffer.subarray(0, headerEnd).toString("ascii"); + const match = /content-length:\s*(\d+)/i.exec(headers); + if (!match) { + this.buffer = this.buffer.subarray(headerEnd + 4); + continue; + } + const length = Number(match[1]); + if (this.buffer.length < headerEnd + 4 + length) break; + out.push(this.buffer.subarray(headerEnd + 4, headerEnd + 4 + length).toString("utf8")); + this.buffer = this.buffer.subarray(headerEnd + 4 + length); + } + return out; + } +} + +export function encode(message: unknown): Buffer { + const body = Buffer.from(JSON.stringify(message), "utf8"); + return Buffer.concat([Buffer.from(`Content-Length: ${body.length}\r\n\r\n`, "ascii"), body]); +} + +export interface BackendOptions { + program: string; + args?: string[]; + cwd?: string; + env?: NodeJS.ProcessEnv; + /** Lines the backend writes to its standard error (its log). */ + log?: (line: string) => void; +} + +/** + * One backend process. `request` sends a method and resolves with its result; `notifications` + * emits each notification by method name (and "*" with the method first). `exited` resolves when + * the process ends. + */ +export class Backend { + readonly notifications = new EventEmitter(); + readonly exited: Promise; + private readonly child: ChildProcess; + private readonly pending = new Map(); + private readonly reader = new FrameReader(); + private nextId = 1; + private alive = true; + + constructor(options: BackendOptions) { + this.notifications.setMaxListeners(0); + this.child = spawn(options.program, options.args ?? ["serve"], { + cwd: options.cwd, + env: options.env ?? process.env, + stdio: ["pipe", "pipe", "pipe"], + windowsHide: true, + }); + this.child.stdout!.on("data", (chunk: Buffer) => { + for (const body of this.reader.feed(chunk)) this.dispatch(body); + }); + let errText = ""; + this.child.stderr!.on("data", (chunk: Buffer) => { + errText += chunk.toString("utf8"); + let nl: number; + while ((nl = errText.indexOf("\n")) >= 0) { + options.log?.(errText.slice(0, nl)); + errText = errText.slice(nl + 1); + } + }); + this.exited = new Promise((resolve) => { + const done = (code: number | null) => { + if (!this.alive) return; + this.alive = false; + for (const p of this.pending.values()) p.reject(new BackendError(p.method, { code: -32099, message: "the mcpp-ide backend ended" })); + this.pending.clear(); + resolve(code); + }; + this.child.on("exit", (code) => done(code)); + this.child.on("error", (e) => { + options.log?.(`mcpp-ide could not start: ${e.message}`); + done(null); + }); + }); + } + + get running(): boolean { + return this.alive; + } + + request(method: string, params: unknown = {}): Promise { + if (!this.alive) return Promise.reject(new BackendError(method, { code: -32099, message: "the mcpp-ide backend is not running" })); + const id = this.nextId++; + return new Promise((resolve, reject) => { + this.pending.set(id, { resolve: resolve as (v: unknown) => void, reject, method }); + this.child.stdin!.write(encode({ jsonrpc: "2.0", id, method, params })); + }); + } + + notify(method: string, params: unknown = {}): void { + if (this.alive) this.child.stdin!.write(encode({ jsonrpc: "2.0", method, params })); + } + + cancel(id: number): void { + this.notify("$/cancelRequest", { id }); + } + + async stop(): Promise { + if (!this.alive) return; + try { + await Promise.race([this.request("shutdown"), new Promise((r) => setTimeout(r, 2000))]); + } catch { + // ended already + } + this.notify("exit"); + this.child.stdin!.end(); + const ended = await Promise.race([this.exited.then(() => true), new Promise((r) => setTimeout(() => r(false), 3000))]); + if (!ended) this.child.kill(); + } + + private dispatch(body: string): void { + let message: { id?: number; method?: string; params?: unknown; result?: unknown; error?: RpcError }; + try { + message = JSON.parse(body); + } catch { + return; + } + if (message.id !== undefined && message.id !== null && (message.result !== undefined || message.error !== undefined)) { + const p = this.pending.get(message.id); + if (!p) return; + this.pending.delete(message.id); + if (message.error) p.reject(new BackendError(p.method, message.error)); + else p.resolve(message.result); + return; + } + if (message.method) { + this.notifications.emit(message.method, message.params); + this.notifications.emit("*", message.method, message.params); + } + } +} diff --git a/vscode/src/backend/locate.ts b/vscode/src/backend/locate.ts new file mode 100644 index 0000000..e3c7d3e --- /dev/null +++ b/vscode/src/backend/locate.ts @@ -0,0 +1,65 @@ +// Where the backend is: the configured path, the one the extension carries for this system +// (`bin//mcpp-ide[.exe]`), the one xlings installed, then PATH. +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; + +export interface Located { + program: string; + source: "setting" | "bundled" | "xlings" | "PATH"; +} + +/** "linux-x64", "darwin-arm64", "win32-x64": the directory under bin/ for this system. */ +export function platformDir(platform: NodeJS.Platform = process.platform, arch: string = process.arch): string { + return `${platform}-${arch}`; +} + +function executable(name: string, platform: NodeJS.Platform): string { + return platform === "win32" ? `${name}.exe` : name; +} + +function isFile(p: string): boolean { + try { + return fs.statSync(p).isFile(); + } catch { + return false; + } +} + +export function onPath(name: string, env: NodeJS.ProcessEnv = process.env, platform: NodeJS.Platform = process.platform): string | undefined { + const dirs = (env.PATH ?? env.Path ?? "").split(platform === "win32" ? ";" : ":").filter(Boolean); + for (const d of dirs) { + const candidate = path.join(d, executable(name, platform)); + if (isFile(candidate)) return candidate; + } + return undefined; +} + +export function locateBackend(options: { + configured?: string; + extensionRoot: string; + env?: NodeJS.ProcessEnv; + platform?: NodeJS.Platform; + arch?: string; + home?: string; +}): Located | undefined { + const platform = options.platform ?? process.platform; + const env = options.env ?? process.env; + const exe = executable("mcpp-ide", platform); + if (options.configured && options.configured.trim()) { + return { program: options.configured.trim(), source: "setting" }; + } + const bundled = path.join(options.extensionRoot, "bin", platformDir(platform, options.arch ?? process.arch), exe); + if (isFile(bundled)) return { program: bundled, source: "bundled" }; + const home = options.home ?? os.homedir(); + const xlingsHome = env.XLINGS_HOME; + for (const candidate of [ + xlingsHome ? path.join(xlingsHome, "subos", "current", "bin", exe) : undefined, + path.join(home, ".xlings", "subos", "current", "bin", exe), + path.join(home, ".xlings", "subos", "default", "bin", exe), + ]) { + if (candidate && isFile(candidate)) return { program: candidate, source: "xlings" }; + } + const found = onPath("mcpp-ide", env, platform); + return found ? { program: found, source: "PATH" } : undefined; +} diff --git a/vscode/src/backend/mcppls.ts b/vscode/src/backend/mcppls.ts new file mode 100644 index 0000000..ae998e9 --- /dev/null +++ b/vscode/src/backend/mcppls.ts @@ -0,0 +1,18 @@ +// Where the mcppls VS Code extension keeps its server: `/payload/`, or MCPPLS_SERVER. The backend reads its version (languageService/status). +import * as fs from "node:fs"; +import * as path from "node:path"; + +export function mcpplsCandidates(extensionPath: string | undefined, env: NodeJS.ProcessEnv = process.env): string[] { + const out: string[] = []; + if (env.MCPPLS_SERVER) out.push(env.MCPPLS_SERVER); + if (!extensionPath) return out; + const payload = env.MCPPLS_PAYLOAD ? path.resolve(env.MCPPLS_PAYLOAD) : path.join(extensionPath, "payload"); + try { + const manifest = JSON.parse(fs.readFileSync(path.join(payload, "payload.json"), "utf8")) as { server?: { path?: string } }; + if (manifest.server?.path) out.push(path.join(payload, manifest.server.path)); + } catch { + // An installation without a payload answers nothing here; PATH and xlings are tried after. + } + return out; +} diff --git a/vscode/src/commands.ts b/vscode/src/commands.ts new file mode 100644 index 0000000..066d165 --- /dev/null +++ b/vscode/src/commands.ts @@ -0,0 +1,211 @@ +// The commands: every id the extension declares (generated from spec/commands.json) is registered +// at activation and does what its row's `action` says. The adapter maps an action to VS Code's UI; +// which argv runs, what a cleanup costs and what a menu offers are the backend's answers. +import * as vscode from "vscode"; + +import type { Debugging } from "./debug"; +import type { Jobs } from "./jobs"; +import type { Panels } from "./panels"; +import type { Projects } from "./projects"; +import type { CleanPlan, CommandEntry, LanguageServiceStatus, TargetRow } from "./protocol"; +import { runProgram } from "./run"; +import type { Session } from "./session"; +import type { Tasks } from "./tasks"; + +export interface CommandContext { + session: Session; + projects: Projects; + jobs: Jobs; + tasks: Tasks; + panels: Panels; + debugging: Debugging; +} + +/** plan -> the editor's confirmation at the plan's level -> apply. */ +export async function cleanup(c: CommandContext, action: string): Promise { + const root = c.projects.project?.root; + const t = (k: string, ...a: unknown[]) => c.session.t(k, ...a); + const plan = await c.session.request("cache/plan", { action, root }); + if (plan.refusedUntrusted) { void vscode.window.showWarningMessage(t("this action needs a trusted workspace")); return; } + const confirmation: Record = {}; + if (plan.level > 0) { + let preview = ""; + if (typeof plan.preview === "object" && plan.preview.source === "mcpp") preview = plan.preview.text ?? ""; + else if (typeof plan.preview === "object") preview = t("About {0} would be freed ({1} entries).", plan.preview.bytesText, plan.preview.count); + const yes = t("Continue"); + const choice = await vscode.window.showWarningMessage(plan.title, { modal: true, detail: [plan.detail, preview].filter(Boolean).join("\n\n") }, yes); + if (choice !== yes) return; + confirmation.confirmed = true; + confirmation.previewShown = !!plan.preview; + if (plan.acknowledge) { + const ack = t("I understand this affects every mcpp project on this machine"); + if ((await vscode.window.showWarningMessage(plan.title, { modal: true, detail: ack }, ack)) !== ack) return; + confirmation.acknowledged = true; + } + } + await c.jobs.start({ action, root, confirmation }, { + output: (text) => c.session.output.append(text), + finished: (p) => { + if (p.status === "ok") void vscode.window.showInformationMessage(t("mcpp: {0}", plan.title.replace(/\?$/, ""))); + else void vscode.window.showErrorMessage(t("mcpp {0}: {1}", plan.argv.join(" "), p.status)); + }, + }, "cache/apply"); +} + +async function selectTarget(c: CommandContext): Promise { + const t = (k: string, ...a: unknown[]) => c.session.t(k, ...a); + const r = await c.session.request<{ host: string; rows: TargetRow[] }>("targets/list", { root: c.projects.project?.root }); + const pick = await vscode.window.showQuickPick( + r.rows.map((row) => ({ + label: `${row.selected ? "$(check) " : ""}${row.target}`, + description: [row.host ? t("this machine") : "", row.platformText].filter(Boolean).join(" · "), + detail: row.toolchains.map((tc) => `${tc.spec || "—"} (${tc.status})`).join(", ") || undefined, + row, + })), + { title: t("Select the build target"), placeHolder: t("build, run, test, debug and pack use it") }); + if (!pick) return; + await vscode.workspace.getConfiguration().update("mcpp.build.target", pick.row.host ? "" : pick.row.target, vscode.ConfigurationTarget.Workspace); + if (!pick.row.installed && pick.row.pin) { + const install = t("Install"); + if ((await vscode.window.showInformationMessage(t("No toolchain is installed for {0}.", pick.row.target), install)) === install) + await c.jobs.start({ spec: pick.row.pin, target: pick.row.target }, { output: (x) => c.session.output.append(x) }, "toolchains/install"); + } +} + +async function installToolchain(c: CommandContext): Promise { + const spec = await vscode.window.showInputBox({ title: c.session.t("Install an mcpp toolchain"), placeHolder: "gcc@16.1.0, llvm@23.1.3" }); + if (!spec) return; + c.session.output.show(true); + await c.jobs.start({ spec }, { output: (x) => c.session.output.append(x) }, "toolchains/install"); +} + +async function selectDefaultToolchain(c: CommandContext): Promise { + const r = await c.session.request<{ rows: { target: string; spec: string; status: string; default: boolean }[]; host: string }>("toolchains/list", {}); + const rows = r.rows.filter((x) => x.target === r.host && x.spec); + const pick = await vscode.window.showQuickPick(rows.map((x) => ({ label: `${x.default ? "$(check) " : ""}${x.spec}`, description: x.status, spec: x.spec })), + { title: c.session.t("Choose the mcpp global default toolchain") }); + if (!pick) return; + await c.session.request("toolchains/setDefault", { spec: pick.spec }); +} + +async function newProject(c: CommandContext): Promise { + const t = (k: string, ...a: unknown[]) => c.session.t(k, ...a); + const folder = await vscode.window.showOpenDialog({ canSelectFolders: true, canSelectFiles: false, openLabel: t("Create the project here") }); + if (!folder?.[0]) return; + const name = await vscode.window.showInputBox({ title: t("New mcpp project (1/2)"), prompt: t("The project's name, which is also its directory") }); + if (!name) return; + const handle = await c.jobs.start({ parent: folder[0].fsPath, name }, { output: (x) => c.session.output.append(x) }, "project/new"); + const done = await handle.done; + if (done.status !== "ok") { void vscode.window.showErrorMessage(t("mcpp new {0}: {1}", name, done.status)); return; } + const open = t("Open"); + if ((await vscode.window.showInformationMessage(t("Created {0}.", name), open)) === open) + await vscode.commands.executeCommand("vscode.openFolder", vscode.Uri.joinPath(folder[0], name), { forceNewWindow: false }); +} + +async function languageService(c: CommandContext): Promise { + const s = await c.session.request("languageService/status", { candidates: c.session.mcpplsCandidates() }); + const show = s.state === "ok" ? vscode.window.showInformationMessage : vscode.window.showWarningMessage; + const choice = await show(s.message, ...s.actions.map((a) => a.title)); + const action = s.actions.find((a) => a.title === choice); + if (action) await act(action.id); +} + +async function act(id: string): Promise { + if (id === "install") await vscode.commands.executeCommand("workbench.extensions.installExtension", "sunrisepeak.mcpp-language-server"); + else await vscode.commands.executeCommand("workbench.extensions.search", "@id:sunrisepeak.mcpp-language-server"); +} + +async function selfCheck(c: CommandContext): Promise { + const r = await c.session.request<{ backend: { version: string }; checks: { status: string; message: string }[] }>("selfCheck", {}); + const out = c.session.output; + out.appendLine(""); + out.appendLine(`===== mcpp: ${c.session.t("Environment Self-check")} =====`); + out.appendLine(`mcpp-vscode ${c.session.context.extension.packageJSON.version} · VS Code ${vscode.version} · ${process.platform}-${process.arch}`); + out.appendLine(`mcpp-ide ${r.backend.version}`); + for (const check of r.checks) out.appendLine(`${check.status.padEnd(8)} ${check.message}`); + out.appendLine("========================================"); + out.show(true); +} + +async function quickMenu(c: CommandContext): Promise { + const r = await c.session.request<{ items: { command: string; title: string; group: string; enabled: boolean; reason?: string; detail?: string }[] }>( + "menu/quick", { root: c.projects.project?.root, editor: "vscode" }); + const pick = await vscode.window.showQuickPick(r.items.map((i) => ({ + label: i.title, description: i.enabled ? i.group : i.reason, detail: i.detail, command: i.command, enabled: i.enabled, + })), { title: c.session.t("Open the mcpp project and toolchain quick menu") }); + if (pick?.enabled) await vscode.commands.executeCommand(pick.command); +} + +async function forward(c: CommandContext, commands: string[], args: unknown[]): Promise { + const known = await vscode.commands.getCommands(true); + const command = commands.find((x) => known.includes(x)); + if (!command) { + await languageService(c); + return; + } + await vscode.commands.executeCommand(command, ...args); +} + +export async function dispatch(c: CommandContext, entry: CommandEntry, args: unknown[]): Promise { + const a = entry.action; + const root = async () => (await c.projects.require())?.root; + const options = (args[0] && typeof args[0] === "object" ? args[0] : {}) as { filter?: string; bin?: string; root?: string; args?: { filter?: string } }; + switch (a.kind) { + case "job": { + const r = options.root ?? (await root()); + if (!r) return; + const filter = options.filter ?? options.args?.filter; + const exec = await c.tasks.execute(a.job === "test" ? "test" : "build", r, filter ? { args: [filter] } : {}); + if (a.then === "languageService") { + const sub = vscode.tasks.onDidEndTaskProcess((e) => { if (e.execution === exec) { sub.dispose(); void languageService(c); } }); + } + return; + } + case "run": { const r = options.root ?? (await root()); if (r) await runProgram(c.session, r, { bin: options.bin }); return; } + case "debug": await c.debugging.start(); return; + case "cache": await cleanup(c, a.plan!); return; + case "panel": c.panels.show(a.panel === "library" ? "libraries" : a.panel!, { root: c.projects.project?.root, graph: a.graph, id: typeof args[0] === "string" ? args[0] : undefined }); return; + case "cancel": { + const ids = c.jobs.runningIds; + for (const id of ids) await c.session.request("job/cancel", { jobId: id }); + return; + } + case "selectTarget": await selectTarget(c); return; + case "installToolchain": await installToolchain(c); return; + case "selectDefaultToolchain": await selectDefaultToolchain(c); return; + case "newProject": await newProject(c); return; + case "quickMenu": await quickMenu(c); return; + case "selfCheck": await selfCheck(c); return; + case "languageService": await languageService(c); return; + case "forward": await forward(c, a.commands ?? [], args); return; + case "editor": await vscode.commands.executeCommand(a.vscode!, ...(a.args ?? [])); return; + case "rpc": { + const handle = await c.jobs.start({ root: c.projects.project?.root }, { output: (x) => c.session.output.append(x) }, a.method!); + const done = await handle.done; + if (done.status !== "ok") void vscode.window.showErrorMessage(c.session.t("mcpp: {0}", done.status)); + return; + } + } +} + +/** Registers every declared command; the backend's table says what each one does. */ +export function registerCommands(context: vscode.ExtensionContext, c: CommandContext): void { + const declared = (context.extension.packageJSON?.contributes?.commands ?? []) as { command: string }[]; + for (const { command } of declared) { + context.subscriptions.push(vscode.commands.registerCommand(command, async (...args: unknown[]) => { + try { + if (!c.session.commands.length) await c.session.start(); + const entry = c.session.commands.find((x) => x.id === command); + if (!entry) throw new Error(c.session.t("unknown command {0}", command)); + await dispatch(c, entry, args); + } catch (e) { + void vscode.window.showErrorMessage(c.session.t("mcpp: {0}", e instanceof Error ? e.message : String(e))); + } + })); + } + // Commands the views use and the palette does not list. + context.subscriptions.push( + vscode.commands.registerCommand("mcpp.languageServer.act", (id: string) => act(id)), + vscode.commands.registerCommand("mcpp.openProjectPanel", () => c.panels.show("project", { root: c.projects.project?.root })), + ); +} diff --git a/vscode/src/debug.ts b/vscode/src/debug.ts new file mode 100644 index 0000000..f67f355 --- /dev/null +++ b/vscode/src/debug.ts @@ -0,0 +1,66 @@ +// Debugging: a launch configuration of type "mcpp" names what to debug (target, profile, arguments); +// the backend builds the program and answers the configuration of the debugger at hand (CodeLLDB, +// the C/C++ extension, lldb-dap or Native Debug), which this provider returns in its place. A +// program that runs through a runner (an ok image under okrun) is debugged as the runner. +import * as vscode from "vscode"; + +import { availableDebuggers } from "./mapping"; +import type { Projects } from "./projects"; +import type { Session } from "./session"; + +export class Debugging implements vscode.DebugConfigurationProvider, vscode.Disposable { + private readonly disposables: vscode.Disposable[] = []; + + constructor(private readonly session: Session, private readonly projects: Projects) { + this.disposables.push( + vscode.debug.registerDebugConfigurationProvider("mcpp", this), + vscode.debug.registerDebugConfigurationProvider("mcpp", { provideDebugConfigurations: () => [{ type: "mcpp", request: "launch", name: "mcpp: debug" }] }, + vscode.DebugConfigurationProviderTriggerKind.Dynamic), + ); + } + + async resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, config: vscode.DebugConfiguration): Promise { + if (!config.type) Object.assign(config, { type: "mcpp", request: "launch", name: "mcpp: debug" }); + const project = (config.root && { root: config.root as string }) || (await this.projects.require()); + if (!project) return undefined; + const available = availableDebuggers((id) => vscode.extensions.getExtension(id) !== undefined); + if (available.length === 0) { + const install = this.session.t("Install CodeLLDB"); + const choice = await vscode.window.showErrorMessage( + this.session.t("No debugger extension is installed: install CodeLLDB, the C/C++ extension or lldb-dap."), install); + if (choice === install) await vscode.commands.executeCommand("workbench.extensions.search", "@id:vadimcn.vscode-lldb"); + return undefined; + } + try { + const answer = await vscode.window.withProgress( + { location: vscode.ProgressLocation.Window, title: this.session.t("mcpp: building for the debugger…") }, + () => this.session.request<{ engine: string; configuration: vscode.DebugConfiguration & { mcppNote?: string } }>("debug/configuration", { + root: project.root, + ...(config.target !== undefined ? { target: config.target } : {}), + ...(config.profile ? { profile: config.profile } : {}), + ...(config.engine ? { engine: config.engine } : {}), + args: Array.isArray(config.args) ? config.args : [], + available, + platform: process.platform === "darwin" ? "macos" : process.platform === "win32" ? "windows" : "linux", + })); + const { mcppNote, ...resolved } = answer.configuration; + if (mcppNote) this.session.output.appendLine(`mcpp: ${mcppNote}`); + return Object.assign({}, resolved, { name: config.name || resolved.name }); + } catch (e) { + const detail = (e as { error?: { data?: { narration?: string } } }).error?.data?.narration; + if (detail) this.session.output.appendLine(detail); + void vscode.window.showErrorMessage(this.session.t("mcpp: {0}", e instanceof Error ? e.message : String(e))); + return undefined; + } + } + + /** `mcpp.debug`: the same, without a launch.json. */ + async start(): Promise { + const folder = this.projects.project ? vscode.workspace.getWorkspaceFolder(vscode.Uri.file(this.projects.project.root)) : undefined; + await vscode.debug.startDebugging(folder, { type: "mcpp", request: "launch", name: "mcpp: debug" }); + } + + dispose(): void { + this.disposables.forEach((d) => d.dispose()); + } +} diff --git a/vscode/src/diagnostics.ts b/vscode/src/diagnostics.ts new file mode 100644 index 0000000..d2ecd2d --- /dev/null +++ b/vscode/src/diagnostics.ts @@ -0,0 +1,88 @@ +// Problems from mcpp, never from a regular expression over a terminal: each `job/diagnostic` of a +// build goes into the Problems panel located where mcpp says, a job's start clears its project's, +// and the manifest's own problems (`manifest/diagnostics`, `manifest/check`) sit on mcpp.toml. +import * as path from "node:path"; +import * as vscode from "vscode"; + +import { severityOf, zeroBased } from "./mapping"; +import type { Diagnostic } from "./protocol"; +import type { Session } from "./session"; + +const SEVERITY: Record = { + error: vscode.DiagnosticSeverity.Error, + warning: vscode.DiagnosticSeverity.Warning, + information: vscode.DiagnosticSeverity.Information, + hint: vscode.DiagnosticSeverity.Hint, +}; + +export function toVscode(d: Diagnostic): vscode.Diagnostic { + const start = zeroBased(d.range?.start); + const end = zeroBased(d.range?.end); + // A point range is widened to the rest of the line's word by VS Code itself when it is empty. + const range = new vscode.Range(start.line, start.character, end.line, Math.max(end.character, start.character + 1)); + const out = new vscode.Diagnostic(range, d.message, SEVERITY[severityOf(d)]); + out.source = d.source || "mcpp"; + if (d.code) out.code = d.code; + return out; +} + +export class Problems implements vscode.Disposable { + private readonly build = vscode.languages.createDiagnosticCollection("mcpp"); + private readonly manifest = vscode.languages.createDiagnosticCollection("mcpp.toml"); + private readonly byRoot = new Map>(); + private readonly disposables: vscode.Disposable[] = [this.build, this.manifest]; + + constructor(session: Session) { + this.disposables.push( + session.on("job/started", (p: { root: string; kind: string }) => { if (p.kind === "build" || p.kind === "test") this.clear(p.root); }), + session.on("job/diagnostic", (p: Diagnostic & { root: string }) => this.add(p.root, p)), + session.on("job/finished", (p: { root?: string; kind?: string; diagnostics?: Diagnostic[] }) => { + // The envelope's diagnostics that the stream did not already carry (a manifest error ends a + // build before any event). + if (!p.root) return; + for (const d of p.diagnostics ?? []) if (d.path && !this.has(p.root, d)) this.add(p.root, d); + }), + session.on("manifest/diagnostics", (p: { root: string; diagnostics: Diagnostic[] }) => this.setManifest(p.root, p.diagnostics)), + vscode.workspace.onDidSaveTextDocument(async (doc) => { + if (path.basename(doc.fileName) !== "mcpp.toml") return; + try { + const r = await session.request<{ root: string; diagnostics: Diagnostic[] }>("manifest/check", { root: path.dirname(doc.fileName) }); + this.setManifest(r.root, r.diagnostics); + } catch { + // mcpp unavailable: the self-check says why. + } + }), + ); + } + + private has(root: string, d: Diagnostic): boolean { + const list = this.byRoot.get(root)?.get(d.path!) ?? []; + return list.some((x) => x.message === d.message); + } + + private add(root: string, d: Diagnostic): void { + if (!d.path) return; + if (!this.byRoot.has(root)) this.byRoot.set(root, new Map()); + const files = this.byRoot.get(root)!; + const file = path.isAbsolute(d.path) ? d.path : path.join(root, d.path); + const list = files.get(file) ?? []; + list.push(toVscode(d)); + files.set(file, list); + this.build.set(vscode.Uri.file(file), list); + } + + private clear(root: string): void { + for (const file of this.byRoot.get(root)?.keys() ?? []) this.build.delete(vscode.Uri.file(file)); + this.byRoot.delete(root); + } + + private setManifest(root: string, diagnostics: Diagnostic[]): void { + const file = vscode.Uri.file(path.join(root, "mcpp.toml")); + const enabled = vscode.workspace.getConfiguration().get("mcpp.toml.diagnostics.enabled") ?? true; + this.manifest.set(file, enabled ? diagnostics.map(toVscode) : []); + } + + dispose(): void { + this.disposables.forEach((d) => d.dispose()); + } +} diff --git a/vscode/src/extension.ts b/vscode/src/extension.ts new file mode 100644 index 0000000..be06921 --- /dev/null +++ b/vscode/src/extension.ts @@ -0,0 +1,84 @@ +// mcpp for VS Code: the adapter of mcpp-ide. It starts the backend (`mcpp-ide serve`) and maps its +// protocol onto VS Code: tasks in pseudoterminals, the Testing view, debug configurations, the +// Problems panel, the project view, the shared panels, mcpp.toml editing help. Language features of +// C++ files are mcppls's (the extension pack installs it); this extension registers none. +import * as vscode from "vscode"; + +import { dispatch, registerCommands, type CommandContext } from "./commands"; +import { Debugging } from "./debug"; +import { Problems } from "./diagnostics"; +import { Jobs } from "./jobs"; +import { Panels } from "./panels"; +import { ProjectTree } from "./projectTree"; +import { Projects } from "./projects"; +import { Session } from "./session"; +import { StatusBar } from "./status"; +import { Tasks } from "./tasks"; +import { Testing } from "./testing"; +import { registerToml } from "./toml"; + +export interface McppApi { + session: Session; + projects: Projects; +} + +export async function activate(context: vscode.ExtensionContext): Promise { + const output = vscode.window.createOutputChannel("mcpp"); + const session = new Session(context, output); + const projects = new Projects(session); + const jobs = new Jobs(session); + const tasks = new Tasks(session, jobs, projects); + const debugging = new Debugging(session, projects); + // The panels run commands, and the commands open panels: the context is completed once both exist. + const c = { session, projects, jobs, tasks, debugging } as CommandContext; + c.panels = new Panels(context, session, async (command, params) => { + const entry = session.commands.find((x) => x.id === command); + if (!entry) throw new Error(session.t("unknown command {0}", command)); + await dispatch(c, entry, [params?.args ?? params]); + return true; + }); + const panels = c.panels; + context.subscriptions.push(output, session, projects, jobs, tasks, debugging, panels, + new Problems(session), new Testing(session, jobs, projects), new ProjectTree(session, projects, jobs), new StatusBar(session, projects, jobs)); + registerCommands(context, c); + registerToml(context, session); + + const views = () => { + const get = (k: string) => vscode.workspace.getConfiguration().get(k) ?? true; + void vscode.commands.executeCommand("setContext", "mcpp.sidebarHidden", !get("mcpp.views.enabled")); + void vscode.commands.executeCommand("setContext", "mcpp.views.project", get("mcpp.views.project.show")); + void vscode.commands.executeCommand("setContext", "mcpp.views.library", get("mcpp.views.library.show")); + void vscode.commands.executeCommand("setContext", "mcpp.views.cache", get("mcpp.views.cache.show")); + }; + views(); + context.subscriptions.push( + vscode.workspace.onDidChangeConfiguration((e) => { if (e.affectsConfiguration("mcpp.views")) views(); }), + jobs.onDidChangeRunning.event((n) => void vscode.commands.executeCommand("setContext", "mcpp.jobRunning", n > 0)), + // A save builds the file's project when asked to (mcpp.build.onSave); a save while a build + // waits replaces it, and the running one is superseded. + vscode.workspace.onDidSaveTextDocument(async (doc) => { + if (!(vscode.workspace.getConfiguration().get("mcpp.build.onSave") ?? false)) return; + if (!/\.(cppm|cpp|cc|cxx|ixx|mpp|h|hpp|toml|mcpp)$/.test(doc.fileName)) return; + const project = await projects.resolve(); + if (project && doc.fileName.startsWith(project.root)) await tasks.execute("build", project.root); + }), + ); + + if (await session.start()) { + if (vscode.workspace.getConfiguration().get("mcpp.diagnostics.selfCheckOnStartup")) + void vscode.commands.executeCommand("mcpp.selfCheck"); + // The language service is not what it should be: said once, with what to do; activation does not + // wait for an answer. + const ls = session.info?.languageService; + if (ls && ls.state !== "ok") + void vscode.window.showWarningMessage(`mcpp: ${ls.message}`, ...ls.actions.map((a) => a.title)).then((choice) => { + const action = ls.actions.find((a) => a.title === choice); + if (action) void vscode.commands.executeCommand("mcpp.languageServer.act", action.id); + }); + } + return { session, projects }; +} + +export function deactivate(): void { + // Everything registered in activate() is disposed by VS Code; the session stops the backend. +} diff --git a/vscode/src/jobs.ts b/vscode/src/jobs.ts new file mode 100644 index 0000000..f90923d --- /dev/null +++ b/vscode/src/jobs.ts @@ -0,0 +1,105 @@ +// A job of the backend, followed from the moment it is asked for: its notifications can arrive +// before the reply that names its id (the job's thread and the reply race), so everything with an +// id not yet claimed is kept briefly and replayed to the handle that claims it. +import * as vscode from "vscode"; + +import type { JobFinished } from "./protocol"; +import type { Session } from "./session"; + +const JOB_EVENTS = ["job/started", "job/output", "job/plan", "job/progress", "job/diagnostic", "job/artifact", "job/record", "job/finished", "test/result", "test/summary"]; + +export interface JobEvents { + output?(text: string): void; + started?(p: { argv: string[] }): void; + plan?(p: any): void; + progress?(p: { finished: number; total: number }): void; + testResult?(p: any): void; + testSummary?(p: any): void; + finished?(p: JobFinished): void; +} + +export class JobHandle { + readonly done: Promise; + private resolveDone!: (p: JobFinished) => void; + constructor(readonly id: string, private readonly session: Session) { + this.done = new Promise((r) => { this.resolveDone = r; }); + } + cancel(): Promise { + return this.session.request("job/cancel", { jobId: this.id }); + } + /** @internal */ + finish(p: JobFinished): void { + this.resolveDone(p); + } +} + +export class Jobs implements vscode.Disposable { + private readonly unclaimed = new Map(); + private readonly claimed = new Map(); + private readonly running = new Set(); + private readonly disposables: vscode.Disposable[] = []; + readonly onDidChangeRunning = new vscode.EventEmitter(); + + constructor(private readonly session: Session) { + for (const method of JOB_EVENTS) + this.disposables.push(session.on(method, (params: any) => this.route(method, params))); + this.disposables.push(this.onDidChangeRunning); + } + + get runningCount(): number { + return this.running.size; + } + + get runningIds(): string[] { + return [...this.running]; + } + + private route(method: string, params: any): void { + const id: string | undefined = params?.jobId; + if (!id) return; + if (method === "job/started") { this.running.add(id); this.onDidChangeRunning.fire(this.running.size); } + if (method === "job/finished") { this.running.delete(id); this.onDidChangeRunning.fire(this.running.size); } + const owner = this.claimed.get(id); + if (!owner) { + const list = this.unclaimed.get(id) ?? []; + list.push({ method, params }); + this.unclaimed.set(id, list); + // A job nobody claims (started by a panel) is kept only until it ends. + if (method === "job/finished") setTimeout(() => this.unclaimed.delete(id), 30_000); + return; + } + this.deliver(owner, method, params); + } + + private deliver(owner: { events: JobEvents; handle: JobHandle }, method: string, params: any): void { + const e = owner.events; + switch (method) { + case "job/output": e.output?.(params.text); break; + case "job/started": e.started?.(params); break; + case "job/plan": e.plan?.(params); break; + case "job/progress": e.progress?.(params); break; + case "test/result": e.testResult?.(params); break; + case "test/summary": e.testSummary?.(params); break; + case "job/finished": + e.finished?.(params); + owner.handle.finish(params); + this.claimed.delete(params.jobId); + break; + } + } + + /** Asks for a job (`job/start`, or another method that answers a job id) and follows it. */ + async start(params: Record, events: JobEvents, method = "job/start"): Promise { + const { jobId } = await this.session.request<{ jobId: string }>(method, params); + const handle = new JobHandle(jobId, this.session); + const owner = { events, handle }; + this.claimed.set(jobId, owner); + for (const m of this.unclaimed.get(jobId) ?? []) this.deliver(owner, m.method, m.params); + this.unclaimed.delete(jobId); + return handle; + } + + dispose(): void { + this.disposables.forEach((d) => d.dispose()); + } +} diff --git a/vscode/src/mapping.ts b/vscode/src/mapping.ts new file mode 100644 index 0000000..3ed2b08 --- /dev/null +++ b/vscode/src/mapping.ts @@ -0,0 +1,56 @@ +// The protocol's values in VS Code's terms, as pure functions (the unit tests run them without an +// editor): positions, severities, test identities, the debuggers present, the "when" of a command. +import type { Diagnostic, Position } from "./protocol"; + +/** mcpp's positions are 1-based lines and columns; VS Code's are 0-based. */ +export function zeroBased(p: Position | undefined): { line: number; character: number } { + if (!p) return { line: 0, character: 0 }; + return { line: Math.max(0, p.line - 1), character: Math.max(0, p.column - 1) }; +} + +export type Severity = "error" | "warning" | "information" | "hint"; + +export function severityOf(d: Pick): Severity { + switch (d.severity) { + case "error": return "error"; + case "warning": return "warning"; + case "note": case "help": return "hint"; + default: return "information"; + } +} + +/** One identity per test: its project, its workspace member and its name. */ +export function testId(root: string, member: string, test: string): string { + return `${root}::${member}::${test}`; +} + +export function parseTestId(id: string): { root: string; member: string; test: string } | undefined { + const parts = id.split("::"); + if (parts.length < 3) return undefined; + const test = parts.pop()!; + const member = parts.pop()!; + return { root: parts.join("::"), member, test }; +} + +/** The debuggers the backend may configure, from the extensions present. */ +export function availableDebuggers(installed: (id: string) => boolean): string[] { + const out: string[] = []; + if (installed("vadimcn.vscode-lldb")) out.push("lldb"); + if (installed("ms-vscode.cpptools")) out.push("cppdbg"); + if (installed("llvm-vs-code-extensions.lldb-dap")) out.push("lldb-dap"); + if (installed("webfreak.debug")) out.push("gdb"); + return out; +} + +/** The mcppls extension's id on the Marketplace. */ +export const MCPPLS_EXTENSION = "sunrisepeak.mcpp-language-server"; + +/** Substitutes `{0}`, `{1}` in a runtime string. */ +export function format(template: string, args: unknown[]): string { + return args.reduce((text, a, i) => text.split(`{${i}}`).join(String(a)), template); +} + +/** The panel title "mcpp: ", the way every panel of this extension is named. */ +export function panelTitle(title: string): string { + return `mcpp: ${title}`; +} diff --git a/vscode/src/panels.ts b/vscode/src/panels.ts new file mode 100644 index 0000000..3ff4e94 --- /dev/null +++ b/vscode/src/panels.ts @@ -0,0 +1,165 @@ +// The shared panels (../webui) in VS Code: editor-area panels and the sidebar's webview views. The +// panel speaks the backend's protocol through this host (rpc in, notifications out) and asks it for +// what only the editor does: open a file, confirm, write a setting, run a command. +import { randomBytes } from "node:crypto"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as vscode from "vscode"; + +import { MCPPLS_EXTENSION, panelTitle } from "./mapping"; +import type { Session } from "./session"; + +export interface PanelParams { + root?: string; + graph?: string; + id?: string; + focus?: string; +} + +type HostAction = (params: any) => Promise<unknown> | unknown; + +export class Panels implements vscode.Disposable { + private readonly open = new Map<string, vscode.WebviewPanel>(); + private readonly webviews = new Set<vscode.Webview>(); + private readonly disposables: vscode.Disposable[] = []; + private readonly webuiRoot: vscode.Uri; + + constructor(private readonly context: vscode.ExtensionContext, private readonly session: Session, + private readonly runCommand: (command: string, params: any) => Promise<unknown>) { + this.webuiRoot = vscode.Uri.joinPath(context.extensionUri, "webui"); + // Every notification of the backend reaches every panel; each panel takes what it shows. + this.disposables.push(session.on("*", ({ method, params }: { method: string; params: unknown }) => { + for (const w of this.webviews) void w.postMessage({ type: "notify", method, params }); + })); + for (const [view, panel] of [["mcpp.library", "libraries"], ["mcpp.cache", "cache"]] as const) + this.disposables.push(vscode.window.registerWebviewViewProvider(view, { + resolveWebviewView: (v) => { const forget = this.attach(v.webview, panel, () => this.paramsForView()); v.onDidDispose(forget); }, + })); + } + + private paramsForView(): PanelParams { + const editor = vscode.window.activeTextEditor; + const projects = this.session.info?.projects ?? []; + const root = editor ? projects.find((p) => editor.document.uri.fsPath.startsWith(p.root))?.root : undefined; + return { root: root ?? projects[0]?.root }; + } + + /** Opens (or reveals) a panel in the editor area. */ + show(panel: string, params: PanelParams = {}): void { + const key = `${panel}:${params.root ?? ""}:${params.graph ?? ""}:${params.id ?? ""}`; + const existing = this.open.get(key); + if (existing) { existing.reveal(); return; } + const titles: Record<string, string> = { + project: this.session.t("Project"), libraries: this.session.t("Libraries"), library: params.id ?? this.session.t("Libraries"), + cache: this.session.t("Cache"), settings: this.session.t("Settings"), pack: this.session.t("Pack"), + targets: this.session.t("Targets and Platforms"), + graph: params.graph === "modules" ? this.session.t("Module graph") : this.session.t("Dependency graph"), + }; + const p = vscode.window.createWebviewPanel(`mcpp.${panel}`, panelTitle(titles[panel] ?? panel), vscode.ViewColumn.Active, + { enableScripts: true, retainContextWhenHidden: true, localResourceRoots: [this.webuiRoot] }); + p.iconPath = vscode.Uri.joinPath(this.context.extensionUri, "media", "logo.png"); + this.open.set(key, p); + const forget = this.attach(p.webview, panel === "library" ? "libraries" : panel, () => params); + p.onDidDispose(() => { this.open.delete(key); forget(); }); + } + + /** Loads the panel into a webview; the returned function forgets it when the webview ends. */ + private attach(webview: vscode.Webview, panel: string, params: () => PanelParams): () => void { + webview.options = { enableScripts: true, localResourceRoots: [this.webuiRoot] }; + const nonce = randomBytes(16).toString("base64"); + const base = `${webview.asWebviewUri(this.webuiRoot).toString()}/`; + const csp = `default-src 'none'; img-src ${webview.cspSource} data:; style-src ${webview.cspSource} 'unsafe-inline'; script-src 'nonce-${nonce}' ${webview.cspSource};`; + const html = fs.readFileSync(path.join(this.webuiRoot.fsPath, "index.html"), "utf8") + .split("{{base}}").join(base).split("{{csp}}").join(csp).split("{{nonce}}").join(nonce) + .split("{{lang}}").join(vscode.env.language); + this.webviews.add(webview); + const sub = webview.onDidReceiveMessage((m) => this.receive(webview, panel, params, m)); + webview.html = html; + return () => { this.webviews.delete(webview); sub.dispose(); }; + } + + private async receive(webview: vscode.Webview, panel: string, params: () => PanelParams, m: any): Promise<void> { + if (m?.type === "ready") { + await webview.postMessage({ type: "init", panel, params: params(), bundle: this.session.strings, editor: "vscode" }); + return; + } + if (m?.type === "rpc") { + try { + const result = await this.session.request(m.method, m.params); + await webview.postMessage({ type: "rpcResult", id: m.id, result }); + } catch (e) { + const error = (e as { error?: unknown }).error ?? { code: -32603, message: e instanceof Error ? e.message : String(e) }; + await webview.postMessage({ type: "rpcError", id: m.id, error }); + } + return; + } + if (m?.type === "host") { + const action = this.actions()[m.action]; + try { + if (!action) throw new Error(`unknown host action ${m.action}`); + const result = await action(m.params ?? {}); + await webview.postMessage({ type: "hostResult", id: m.id, result: result ?? null }); + } catch (e) { + await webview.postMessage({ type: "hostError", id: m.id, error: { message: e instanceof Error ? e.message : String(e) } }); + } + } + } + + private actions(): Record<string, HostAction> { + const t = (k: string, ...a: unknown[]) => this.session.t(k, ...a); + const target = (key: string) => { + const i = vscode.workspace.getConfiguration().inspect(key); + if (i?.workspaceFolderValue !== undefined) return vscode.ConfigurationTarget.WorkspaceFolder; + if (i?.workspaceValue !== undefined) return vscode.ConfigurationTarget.Workspace; + return vscode.ConfigurationTarget.Global; + }; + return { + settings: () => this.session.settings(), + setSetting: async (p) => { await vscode.workspace.getConfiguration().update(p.key, p.value, target(p.key)); return true; }, + resetSettings: async (p) => { + for (const key of p.keys as string[]) await vscode.workspace.getConfiguration().update(key, undefined, target(key)); + return true; + }, + migrateSettings: async (p) => { + for (const r of p.renames as { from: string; to: string }[]) { + const i = vscode.workspace.getConfiguration().inspect(r.from); + if (i?.globalValue !== undefined) await vscode.workspace.getConfiguration().update(r.to, i.globalValue, vscode.ConfigurationTarget.Global); + if (i?.workspaceValue !== undefined) await vscode.workspace.getConfiguration().update(r.to, i.workspaceValue, vscode.ConfigurationTarget.Workspace); + } + return true; + }, + openFile: async (p) => { + const doc = await vscode.workspace.openTextDocument(vscode.Uri.file(p.path)); + const line = Math.max(0, (p.line ?? 1) - 1); + await vscode.window.showTextDocument(doc, { selection: new vscode.Range(line, 0, line, 0) }); + return true; + }, + openExternal: (p) => vscode.env.openExternal(vscode.Uri.parse(p.url)), + reveal: (p) => vscode.commands.executeCommand("revealFileInOS", vscode.Uri.file(p.path)), + copy: async (p) => { await vscode.env.clipboard.writeText(p.text); void vscode.window.showInformationMessage(t("Copied.")); return true; }, + notify: (p) => (p.level === "error" ? vscode.window.showErrorMessage(p.message) : p.level === "warning" ? vscode.window.showWarningMessage(p.message) : vscode.window.showInformationMessage(p.message)), + openPanel: (p) => { const { panel, ...rest } = p; this.show(panel, rest); return true; }, + runCommand: (p) => this.runCommand(p.command, p), + confirm: async (p) => { + const yes = t("Continue"); + const detail = [p.detail, p.preview].filter(Boolean).join("\n\n"); + const choice = await vscode.window.showWarningMessage(p.title, { modal: true, detail }, yes); + if (choice !== yes) return { confirmed: false }; + if (!p.acknowledge) return { confirmed: true }; + const ack = t("I understand this affects every mcpp project on this machine"); + const second = await vscode.window.showWarningMessage(p.title, { modal: true, detail: ack }, ack); + return { confirmed: second === ack, acknowledged: second === ack }; + }, + languageService: async (p) => { + if (p.action === "install") await vscode.commands.executeCommand("workbench.extensions.installExtension", MCPPLS_EXTENSION); + else await vscode.commands.executeCommand("workbench.extensions.search", `@id:${MCPPLS_EXTENSION}`); + return true; + }, + }; + } + + dispose(): void { + for (const p of this.open.values()) p.dispose(); + this.disposables.forEach((d) => d.dispose()); + } +} diff --git a/vscode/src/projectTree.ts b/vscode/src/projectTree.ts new file mode 100644 index 0000000..becb336 --- /dev/null +++ b/vscode/src/projectTree.ts @@ -0,0 +1,117 @@ +// The project view (mcpp.project): the current project's executables, tests and libraries, the +// target it builds for and the platform that configures it, its last build, and the language +// service that answers its sources. Everything shown is the backend's `project/summary` and +// `languageService/status`. +import * as vscode from "vscode"; + +import type { Jobs } from "./jobs"; +import type { Projects } from "./projects"; +import type { LanguageServiceStatus, ProjectSummary } from "./protocol"; +import type { Session } from "./session"; + +class Node extends vscode.TreeItem { + children?: Node[]; + constructor(label: string, opts: { description?: string; icon?: string; context?: string; command?: vscode.Command; tooltip?: string; children?: Node[]; expanded?: boolean } = {}) { + super(label, opts.children ? (opts.expanded === false ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.Expanded) : vscode.TreeItemCollapsibleState.None); + this.description = opts.description; + if (opts.icon) this.iconPath = new vscode.ThemeIcon(opts.icon); + this.contextValue = opts.context; + this.command = opts.command; + this.tooltip = opts.tooltip; + this.children = opts.children; + } +} + +export class ProjectTree implements vscode.TreeDataProvider<Node>, vscode.Disposable { + private readonly changed = new vscode.EventEmitter<void>(); + readonly onDidChangeTreeData = this.changed.event; + private readonly disposables: vscode.Disposable[] = []; + private summary: ProjectSummary | undefined; + private languageService: LanguageServiceStatus | undefined; + private error: string | undefined; + + constructor(private readonly session: Session, private readonly projects: Projects, private readonly jobs: Jobs) { + const refresh = () => void this.load(); + this.disposables.push( + this.changed, + vscode.window.registerTreeDataProvider("mcpp.project", this), + projects.onDidChange.event(refresh), + session.on("result/changed", refresh), + session.on("manifest/changed", refresh), + session.on("job/plan", refresh), + jobs.onDidChangeRunning.event(() => this.changed.fire()), + vscode.workspace.onDidChangeConfiguration((e) => { if (e.affectsConfiguration("mcpp.build.target")) refresh(); }), + vscode.extensions.onDidChange(refresh), + ); + } + + async load(): Promise<void> { + const project = this.projects.project; + this.error = undefined; + if (!project) { this.summary = undefined; this.changed.fire(); return; } + try { + [this.summary, this.languageService] = await Promise.all([ + this.session.request<ProjectSummary>("project/summary", { root: project.root }), + this.session.request<LanguageServiceStatus>("languageService/status", { candidates: this.session.mcpplsCandidates() }), + ]); + } catch (e) { + this.error = e instanceof Error ? e.message : String(e); + } + this.changed.fire(); + } + + getTreeItem(n: Node): vscode.TreeItem { + return n; + } + + getChildren(n?: Node): Node[] { + if (n) return n.children ?? []; + const t = (k: string, ...a: unknown[]) => this.session.t(k, ...a); + const project = this.projects.project; + if (!project) return [new Node(t("No mcpp project in this workspace"), { icon: "info" })]; + if (this.error) return [new Node(t("mcpp could not answer"), { icon: "error", tooltip: this.error, command: { command: "mcpp.selfCheck", title: "" } })]; + const s = this.summary; + if (!s) return [new Node(t("Loading…"), { icon: "loading~spin" })]; + const cmd = (command: string, ...args: unknown[]): vscode.Command => ({ command, title: "", arguments: args }); + const out: Node[] = []; + out.push(new Node(project.name, { + description: s.toolchain, icon: "project", tooltip: project.root, + command: cmd("mcpp.openProjectPanel"), + })); + out.push(new Node(t("Target"), { + description: `${s.target || t("this machine")}${s.platformText ? ` · ${s.platformText}` : ""}`, icon: "target", + command: cmd("mcpp.selectTarget"), tooltip: s.hostPlatformText ? `${t("Host platform")}: ${s.hostPlatformText}` : undefined, + })); + if (s.lastBuild) { + const ok = s.lastBuild.status === "ok"; + out.push(new Node(t("Last build"), { description: `${s.lastBuild.status}${s.lastBuild.client ? ` · ${s.lastBuild.client}` : ""}`, icon: ok ? "pass" : "error" })); + } + if (this.jobs.runningCount > 0) + out.push(new Node(t("{0} job(s) running", this.jobs.runningCount), { icon: "sync~spin", command: cmd("mcpp.cancelJob"), tooltip: t("Cancel the Running Job") })); + out.push(new Node(t("Executables"), { icon: "symbol-event", children: s.targets.map((x) => + new Node(x.name, { icon: "play", context: "mcppExecutable", command: cmd("mcpp.run", { bin: x.name }) })) })); + out.push(new Node(t("Tests"), { icon: "beaker", children: s.tests.map((x) => + new Node(x.name, { icon: "beaker", context: "mcppTest", command: cmd("mcpp.test", { filter: x.name }) })) })); + out.push(new Node(t("Libraries"), { icon: "library", expanded: false, children: s.libraries.map((x) => new Node(x.name, { description: x.kind, icon: "package" })) })); + out.push(new Node(t("Dependencies"), { icon: "type-hierarchy", context: "mcppProjectDependencies", command: cmd("mcpp.project.showDependencyGraph") })); + const ls = this.languageService; + if (ls) { + const state = ls.state === "ok" ? "pass" : ls.state === "missing" ? "error" : "warning"; + out.push(new Node(t("C++ Modules language service"), { + description: ls.state === "ok" ? `mcppls ${ls.version}` : t("needs attention"), icon: state, tooltip: ls.message, + children: [ + new Node(ls.message, { icon: "info", tooltip: ls.message }), + ...ls.actions.map((a) => new Node(a.title, { icon: "cloud-download", command: cmd("mcpp.languageServer.act", a.id) })), + new Node(t("Restart the language server"), { icon: "debug-restart", command: cmd("mcpp.languageServer.restart") }), + new Node(t("Open the log"), { icon: "output", command: cmd("mcpp.languageServer.showLogs") }), + ], + expanded: ls.state !== "ok", + })); + } + return out; + } + + dispose(): void { + this.disposables.forEach((d) => d.dispose()); + } +} diff --git a/vscode/src/projects.ts b/vscode/src/projects.ts new file mode 100644 index 0000000..136efe9 --- /dev/null +++ b/vscode/src/projects.ts @@ -0,0 +1,69 @@ +// Which project the user is in: the one the active editor's file belongs to (the backend answers, +// `projects/forFile`), else the first project of the window. The answer sets `mcpp.inProject` and +// `mcpp.editorTitleButtons`, which the generated menus and keybindings read. +import * as vscode from "vscode"; + +import type { Project } from "./protocol"; +import type { Session } from "./session"; + +export class Projects implements vscode.Disposable { + private current: Project | undefined; + private readonly disposables: vscode.Disposable[] = []; + readonly onDidChange = new vscode.EventEmitter<Project | undefined>(); + + constructor(private readonly session: Session) { + this.disposables.push( + this.onDidChange, + vscode.window.onDidChangeActiveTextEditor(() => void this.refresh()), + vscode.workspace.onDidChangeWorkspaceFolders(() => void this.refresh()), + vscode.workspace.onDidChangeConfiguration((e) => { if (e.affectsConfiguration("mcpp.task.editorTitleButtons")) void this.refresh(); }), + session.onDidStart.event(() => void this.refresh()), + ); + } + + get project(): Project | undefined { + return this.current; + } + + get all(): Project[] { + return this.session.info?.projects ?? []; + } + + /** The current project, asking the backend if the answer is not known yet. */ + async resolve(): Promise<Project | undefined> { + if (!this.current) await this.refresh(); + return this.current; + } + + async refresh(): Promise<void> { + let next: Project | undefined; + const editor = vscode.window.activeTextEditor; + try { + if (editor && editor.document.uri.scheme === "file") { + const folder = vscode.workspace.getWorkspaceFolder(editor.document.uri); + const boundary = vscode.workspace.getConfiguration().get<string>("mcpp.project.discoveryBoundary") === "filesystem" ? "" : folder?.uri.fsPath ?? ""; + next = (await this.session.request<Project | null>("projects/forFile", { path: editor.document.uri.fsPath, boundary })) ?? undefined; + } + } catch { + next = undefined; + } + if (!next) next = this.current && this.all.some((p) => p.root === this.current!.root) ? this.current : this.all[0]; + const changed = next?.root !== this.current?.root; + this.current = next; + await vscode.commands.executeCommand("setContext", "mcpp.inProject", !!next); + await vscode.commands.executeCommand("setContext", "mcpp.editorTitleButtons", + vscode.workspace.getConfiguration().get<boolean>("mcpp.task.editorTitleButtons") ?? true); + if (changed) this.onDidChange.fire(next); + } + + /** The current project, or a message that there is none. */ + async require(): Promise<Project | undefined> { + const p = await this.resolve(); + if (!p) void vscode.window.showWarningMessage(this.session.t("No mcpp.toml was found in this workspace. Run this command inside an mcpp project.")); + return p; + } + + dispose(): void { + this.disposables.forEach((d) => d.dispose()); + } +} diff --git a/vscode/src/protocol.ts b/vscode/src/protocol.ts new file mode 100644 index 0000000..167bfaf --- /dev/null +++ b/vscode/src/protocol.ts @@ -0,0 +1,150 @@ +// The shapes of protocol/protocol.schema.json this adapter reads. The schema is the authority; these +// declarations only name what the code below touches. + +export interface Project { + root: string; + workspaceRoot: string; + name: string; + isWorkspaceRoot: boolean; +} + +export interface Check { + id: string; + status: "ok" | "info" | "warning" | "error"; + message: string; +} + +export interface LanguageServiceStatus { + state: "ok" | "outdated" | "missing" | "unreadable"; + program: string; + source: string; + version: string; + required: string; + message: string; + actions: { id: "install" | "update"; title: string }[]; +} + +export interface InitializeResult { + server: { name: string; version: string }; + protocol: number; + mcpp: { path: string; version: string; contract: boolean } | null; + languageService: LanguageServiceStatus | null; + checks: Check[]; + projects: Project[]; + capabilities: string[]; +} + +export interface CommandAction { + kind: string; + job?: string; + plan?: string; + panel?: string; + graph?: string; + method?: string; + commands?: string[]; + vscode?: string; + args?: unknown[]; + then?: string; + refresh?: boolean; +} + +export interface CommandEntry { + id: string; + title: string; + group: string; + groupTitle: string; + when?: string; + quickMenu?: boolean; + deprecated?: boolean; + action: CommandAction; +} + +export interface Position { + line: number; + column: number; +} + +export interface Diagnostic { + severity: string; + message: string; + code?: string; + path?: string; + range?: { start: Position; end: Position }; + source?: string; +} + +export interface Platform { + name?: string; + version?: string | null; + source?: string; + fields?: Record<string, { value?: unknown; source?: string }>; +} + +export interface ProjectSummary { + root: string; + targets: { name: string; kind: string; configuration: string }[]; + tests: { name: string; kind: string; configuration: string }[]; + libraries: { name: string; kind: string; configuration: string }[]; + toolchain: string; + target?: string | null; + lastBuild?: { status: string; finishedAt?: number | null; client?: string; command?: string }; + artifacts?: { kind: string; name: string; path: string }[]; + platform?: Platform | null; + platformText?: string; + hostPlatformText?: string; + error?: string; +} + +export interface Launch { + argv: string[]; + cwd: string; + env: Record<string, string>; + program?: string; + via?: string | null; +} + +export interface TargetRow { + target: string; + note: string; + pin: string; + host: boolean; + toolchains: { spec: string; status: string; default: boolean }[]; + platform: Platform | null; + platformText: string; + selected: boolean; + installed: boolean; +} + +export interface CleanPlan { + action: string; + argv: string[]; + level: number; + preview: boolean | { source: string; text?: string; bytesText?: string; count?: number }; + acknowledge: boolean; + title: string; + detail: string; + refusedUntrusted: boolean; +} + +export interface JobFinished { + jobId: string; + status: "ok" | "failed" | "cancelled" | "denied" | "superseded"; + exitCode: number | null; + durationMs?: number; + root?: string; + kind?: string; + envelope?: { kind?: string; data?: unknown }; + diagnostics?: Diagnostic[]; + artifacts?: { kind: string; name: string; path: string }[]; +} + +export interface TestResult { + jobId: string; + root: string; + member: string; + test: string; + status: "passed" | "failed" | "timedOut" | "skipped" | "errored"; + durationMs: number; + output: string; + reason: string; +} diff --git a/vscode/src/run.ts b/vscode/src/run.ts new file mode 100644 index 0000000..a77bb01 --- /dev/null +++ b/vscode/src/run.ts @@ -0,0 +1,27 @@ +// Running: the backend builds the program and answers how it starts (mcpp run --print-launch: argv, +// the environment mcpp adds, the working directory, the runner); the program then runs in a terminal +// of its own, where it reads input and its colours are its own. +import * as vscode from "vscode"; + +import type { Launch } from "./protocol"; +import type { Session } from "./session"; + +export async function runProgram(session: Session, root: string, options: { target?: string; bin?: string } = {}): Promise<void> { + const args = vscode.workspace.getConfiguration().get<string[]>("mcpp.task.runArgs") ?? []; + let launch: Launch; + try { + launch = await vscode.window.withProgress( + { location: vscode.ProgressLocation.Window, title: session.t("mcpp: building…") }, + () => session.request<Launch>("run/launch", { root, args, ...(options.target !== undefined ? { target: options.target } : {}), ...(options.bin ? { bin: options.bin } : {}) })); + } catch (e) { + const data = (e as { error?: { data?: { narration?: string } } }).error?.data; + if (data?.narration) { session.output.appendLine(data.narration); session.output.show(true); } + void vscode.window.showErrorMessage(session.t("mcpp: {0}", e instanceof Error ? e.message : String(e))); + return; + } + const [program, ...rest] = launch.argv; + const name = `mcpp run: ${(launch.program ?? program).split(/[\\/]/).pop()}`; + vscode.window.terminals.find((t) => t.name === name)?.dispose(); + const terminal = vscode.window.createTerminal({ name, shellPath: program, shellArgs: rest, cwd: launch.cwd, env: launch.env }); + terminal.show(!(vscode.workspace.getConfiguration().get<boolean>("mcpp.task.focusTerminal") ?? true)); +} diff --git a/vscode/src/session.ts b/vscode/src/session.ts new file mode 100644 index 0000000..ba3d9ae --- /dev/null +++ b/vscode/src/session.ts @@ -0,0 +1,177 @@ +// The session with the backend: started at activation, given the editor's settings, trust, +// language and folders, kept current as they change, and restarted (once, then on request) when it +// ends. Everything else in the adapter reaches the backend through `session.request`. +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as vscode from "vscode"; + +import { Backend, BackendError } from "./backend/client"; +import { locateBackend, type Located } from "./backend/locate"; +import { mcpplsCandidates } from "./backend/mcppls"; +import { format, MCPPLS_EXTENSION } from "./mapping"; +import type { CommandEntry, InitializeResult } from "./protocol"; + +export class Session implements vscode.Disposable { + private backend: Backend | undefined; + private located: Located | undefined; + private initResult: InitializeResult | undefined; + private bundle: Record<string, string> = {}; + private commandTable: CommandEntry[] = []; + private restarts = 0; + private starting: Promise<boolean> | undefined; + private readonly disposables: vscode.Disposable[] = []; + private readonly listeners = new Map<string, Set<(params: any) => void>>(); + readonly onDidStart = new vscode.EventEmitter<InitializeResult>(); + + constructor(readonly context: vscode.ExtensionContext, readonly output: vscode.OutputChannel) { + // The strings the extension carries (spec/i18n/runtime.zh-cn.json): what is said before the + // backend runs, or when it cannot. + if (vscode.env.language.toLowerCase().startsWith("zh")) { + try { + this.bundle = JSON.parse(fs.readFileSync(path.join(context.extensionPath, "i18n", "runtime.zh-cn.json"), "utf8")); + } catch { + this.bundle = {}; + } + } + this.disposables.push( + this.onDidStart, + vscode.workspace.onDidChangeConfiguration((e) => { + if (e.affectsConfiguration("mcpp.ide.backendPath")) { void this.restart(); return; } + if (e.affectsConfiguration("mcpp")) void this.pushSettings(); + }), + vscode.workspace.onDidGrantWorkspaceTrust(() => void this.pushSettings()), + vscode.workspace.onDidChangeWorkspaceFolders(() => void this.restart()), + vscode.extensions.onDidChange(() => void this.request("languageService/status", { candidates: this.mcpplsCandidates() }).catch(() => undefined)), + ); + } + + get info(): InitializeResult | undefined { + return this.initResult; + } + + get commands(): CommandEntry[] { + return this.commandTable; + } + + /** A runtime string in the session's language. */ + t(key: string, ...args: unknown[]): string { + return format(this.bundle[key] ?? key, args); + } + + /** The bundle for webviews, which translate on their own. */ + get strings(): Record<string, string> { + return this.bundle; + } + + /** Every mcpp.* value, as VS Code resolves it for the window. */ + settings(): Record<string, unknown> { + const out: Record<string, unknown> = {}; + const props = (this.context.extension.packageJSON?.contributes?.configuration?.properties ?? {}) as Record<string, unknown>; + const config = vscode.workspace.getConfiguration(); + for (const key of Object.keys(props)) out[key] = config.get(key); + return out; + } + + mcpplsCandidates(): string[] { + return mcpplsCandidates(vscode.extensions.getExtension(MCPPLS_EXTENSION)?.extensionPath); + } + + on(method: string, fn: (params: any) => void): vscode.Disposable { + if (!this.listeners.has(method)) this.listeners.set(method, new Set()); + this.listeners.get(method)!.add(fn); + return new vscode.Disposable(() => this.listeners.get(method)?.delete(fn)); + } + + async start(): Promise<boolean> { + if (this.starting) return this.starting; + this.starting = this.doStart().finally(() => { this.starting = undefined; }); + return this.starting; + } + + private async doStart(): Promise<boolean> { + const configured = vscode.workspace.getConfiguration().get<string>("mcpp.ide.backendPath") ?? ""; + this.located = locateBackend({ configured: vscode.workspace.isTrusted ? configured : "", extensionRoot: this.context.extensionPath }); + if (!this.located) { + const message = this.t("The mcpp-ide backend was not found. Install it with `xlings install mcpp-ide`, or set mcpp.ide.backendPath."); + this.output.appendLine(`mcpp: ${message}`); + const open = this.t("Open Settings"); + void vscode.window.showErrorMessage(`mcpp: ${message}`, open).then((c) => { + if (c === open) void vscode.commands.executeCommand("workbench.action.openSettings", "mcpp.ide.backendPath"); + }); + return false; + } + this.output.appendLine(`mcpp-ide: starting ${this.located.program} (${this.located.source})`); + const backend = new Backend({ + program: this.located.program, + log: (line) => this.output.appendLine(`[backend] ${line}`), + }); + this.backend = backend; + backend.notifications.on("*", (method: string, params: unknown) => { + for (const fn of this.listeners.get(method) ?? []) { + try { fn(params); } catch (e) { this.output.appendLine(`mcpp: ${method}: ${String(e)}`); } + } + for (const fn of this.listeners.get("*") ?? []) fn({ method, params }); + }); + void backend.exited.then((code) => this.onExit(backend, code)); + try { + const folders = (vscode.workspace.workspaceFolders ?? []).map((f) => f.uri.fsPath); + this.initResult = await backend.request<InitializeResult>("initialize", { + client: { name: "VS Code", version: vscode.version }, + editor: "vscode", + locale: vscode.env.language, + trusted: vscode.workspace.isTrusted, + settings: this.settings(), + workspaceFolders: folders, + languageService: { candidates: this.mcpplsCandidates() }, + }); + this.bundle = await backend.request<Record<string, string>>("i18n/bundle", {}); + this.commandTable = (await backend.request<{ commands: CommandEntry[] }>("commands/list", { editor: "vscode" })).commands; + for (const c of this.initResult.checks) if (c.status === "error") this.output.appendLine(`mcpp: ${c.message}`); + this.onDidStart.fire(this.initResult); + return true; + } catch (e) { + this.output.appendLine(`mcpp-ide: initialize failed: ${String(e)}`); + return false; + } + } + + private onExit(backend: Backend, code: number | null): void { + if (backend !== this.backend) return; + this.backend = undefined; + this.output.appendLine(`mcpp-ide: the backend ended (${code ?? "signal"})`); + if (this.restarts < 1) { + ++this.restarts; + void this.start(); + return; + } + const again = this.t("Restart"); + void vscode.window.showErrorMessage(`mcpp: ${this.t("The mcpp-ide backend ended.")}`, again).then((c) => { + if (c === again) { this.restarts = 0; void this.start(); } + }); + } + + async restart(): Promise<void> { + const old = this.backend; + this.backend = undefined; + if (old) await old.stop(); + this.restarts = 0; + await this.start(); + } + + async request<T = unknown>(method: string, params: unknown = {}): Promise<T> { + if (!this.backend?.running) { + if (!(await this.start())) throw new BackendError(method, { code: -32099, message: this.t("the mcpp-ide backend is not running") }); + } + return this.backend!.request<T>(method, params); + } + + async pushSettings(): Promise<void> { + if (!this.backend?.running) return; + await this.backend.request("settings/update", { settings: this.settings(), trusted: vscode.workspace.isTrusted, locale: vscode.env.language }); + } + + dispose(): void { + this.disposables.forEach((d) => d.dispose()); + void this.backend?.stop(); + } +} diff --git a/vscode/src/status.ts b/vscode/src/status.ts new file mode 100644 index 0000000..458c8be --- /dev/null +++ b/vscode/src/status.ts @@ -0,0 +1,49 @@ +// The status bar: the target the project builds for (and its platform), and whether a job runs. +// A click on the first selects another target; on the second, cancels the running jobs. +import * as vscode from "vscode"; + +import type { Jobs } from "./jobs"; +import type { Projects } from "./projects"; +import type { Session } from "./session"; + +export class StatusBar implements vscode.Disposable { + private readonly target = vscode.window.createStatusBarItem("mcpp.target", vscode.StatusBarAlignment.Left, 50); + private readonly job = vscode.window.createStatusBarItem("mcpp.job", vscode.StatusBarAlignment.Left, 49); + private readonly disposables: vscode.Disposable[] = [this.target, this.job]; + private platformText = ""; + + constructor(private readonly session: Session, private readonly projects: Projects, private readonly jobs: Jobs) { + this.target.name = "mcpp target"; + this.target.command = "mcpp.selectTarget"; + this.job.name = "mcpp job"; + this.job.command = "mcpp.cancelJob"; + this.disposables.push( + projects.onDidChange.event(() => this.update()), + jobs.onDidChangeRunning.event(() => this.update()), + session.on("job/plan", (p: { root: string; platformText?: string }) => { + if (p.root === projects.project?.root) { this.platformText = p.platformText ?? ""; this.update(); } + }), + vscode.workspace.onDidChangeConfiguration((e) => { if (e.affectsConfiguration("mcpp.build.target") || e.affectsConfiguration("mcpp.ui.statusBar.show")) this.update(); }), + ); + this.update(); + } + + private update(): void { + const t = (k: string, ...a: unknown[]) => this.session.t(k, ...a); + const show = vscode.workspace.getConfiguration().get<boolean>("mcpp.ui.statusBar.show") ?? true; + if (!show || !this.projects.project) { this.target.hide(); this.job.hide(); return; } + const target = vscode.workspace.getConfiguration().get<string>("mcpp.build.target") || t("this machine"); + this.target.text = `$(target) ${target}`; + this.target.tooltip = [t("The target build, run, test, debug and pack use"), this.platformText].filter(Boolean).join("\n"); + this.target.show(); + if (this.jobs.runningCount > 0) { + this.job.text = `$(sync~spin) mcpp`; + this.job.tooltip = t("{0} job(s) running", this.jobs.runningCount); + this.job.show(); + } else this.job.hide(); + } + + dispose(): void { + this.disposables.forEach((d) => d.dispose()); + } +} diff --git a/vscode/src/tasks.ts b/vscode/src/tasks.ts new file mode 100644 index 0000000..952bfc8 --- /dev/null +++ b/vscode/src/tasks.ts @@ -0,0 +1,115 @@ +// mcpp's builds and tests as VS Code tasks (type "mcpp"): each runs as a backend job in a +// pseudoterminal that shows mcpp's own narration, in colour, and ends with the job's exit code. +// Closing the terminal cancels the job; mcpp then ends the steps it started and records the build as +// cancelled. A task's problems come from mcpp's diagnostics (diagnostics.ts), not from a matcher. +import * as vscode from "vscode"; + +import type { Jobs, JobHandle } from "./jobs"; +import type { Projects } from "./projects"; +import type { Session } from "./session"; + +export interface McppTaskDefinition extends vscode.TaskDefinition { + type: "mcpp"; + command: "build" | "test" | "run" | "clean"; + target?: string; + profile?: "dev" | "release"; + args?: string[]; + root?: string; +} + +/** A terminal that renders one backend job. */ +export class JobTerminal implements vscode.Pseudoterminal { + private readonly writeEmitter = new vscode.EventEmitter<string>(); + private readonly closeEmitter = new vscode.EventEmitter<number>(); + readonly onDidWrite = this.writeEmitter.event; + readonly onDidClose = this.closeEmitter.event; + private handle: JobHandle | undefined; + private ended = false; + + constructor(private readonly start: (term: JobTerminal) => Promise<JobHandle | undefined>, private readonly session: Session) {} + + print(text: string): void { + this.writeEmitter.fire(text.replace(/\r?\n/g, "\r\n")); + } + + end(code: number): void { + if (this.ended) return; + this.ended = true; + this.closeEmitter.fire(code); + } + + open(): void { + if (vscode.workspace.getConfiguration().get<boolean>("mcpp.task.clearTerminal")) this.writeEmitter.fire("\x1bc"); + this.start(this).then((h) => { this.handle = h; if (!h) this.end(1); }, (e) => { + this.print(`\x1b[31m${this.session.t("mcpp: {0}", e instanceof Error ? e.message : String(e))}\x1b[0m\n`); + this.end(1); + }); + } + + close(): void { + // The terminal closed while the job runs: ask mcpp to end it. + if (!this.ended && this.handle) void this.handle.cancel(); + } +} + +export class Tasks implements vscode.TaskProvider, vscode.Disposable { + private readonly registration: vscode.Disposable; + + constructor(private readonly session: Session, private readonly jobs: Jobs, private readonly projects: Projects) { + this.registration = vscode.tasks.registerTaskProvider("mcpp", this); + } + + provideTasks(): vscode.Task[] { + const root = this.projects.project?.root; + if (!root) return []; + return (["build", "test"] as const).map((command) => this.task({ type: "mcpp", command }, root)); + } + + resolveTask(task: vscode.Task): vscode.Task | undefined { + const def = task.definition as McppTaskDefinition; + return this.task(def, def.root || this.projects.project?.root || "", task.scope); + } + + task(def: McppTaskDefinition, root: string, scope?: vscode.WorkspaceFolder | vscode.TaskScope): vscode.Task { + const folder = scope ?? vscode.workspace.getWorkspaceFolder(vscode.Uri.file(root)) ?? vscode.TaskScope.Workspace; + const execution = new vscode.CustomExecution(async () => new JobTerminal((term) => this.run(def, root, term), this.session)); + const task = new vscode.Task(def, folder, def.command, "mcpp", execution, []); + task.group = def.command === "build" ? vscode.TaskGroup.Build : def.command === "test" ? vscode.TaskGroup.Test : undefined; + const reveal = vscode.workspace.getConfiguration().get<string>("mcpp.task.revealTerminal"); + task.presentationOptions = { + reveal: reveal === "never" ? vscode.TaskRevealKind.Never : reveal === "silent" ? vscode.TaskRevealKind.Silent : vscode.TaskRevealKind.Always, + focus: vscode.workspace.getConfiguration().get<boolean>("mcpp.task.focusTerminal") ?? false, + clear: false, + }; + return task; + } + + private async run(def: McppTaskDefinition, root: string, term: JobTerminal): Promise<JobHandle | undefined> { + if (!root) { term.print(`${this.session.t("No mcpp project in this workspace")}\n`); return undefined; } + const params: Record<string, unknown> = { kind: def.command === "test" ? "test" : "build", root, color: true, supersede: true }; + if (def.target !== undefined) params.target = def.target; + if (def.profile) params.profile = def.profile; + if (def.args?.length) params.args = def.args; + const handle = await this.jobs.start(params, { + output: (text) => term.print(text), + testResult: (r) => { + const mark = r.status === "passed" ? "\x1b[32m✓\x1b[0m" : r.status === "skipped" ? "-" : "\x1b[31m✗\x1b[0m"; + term.print(`${mark} ${r.test} (${r.durationMs} ms)\n`); + }, + finished: (p) => { + term.print(`\n${p.status === "ok" ? "\x1b[32m" : "\x1b[31m"}${this.session.t("mcpp {0}: {1}", def.command, p.status)}\x1b[0m\n`); + term.end(p.exitCode ?? (p.status === "ok" ? 0 : 1)); + }, + }); + return handle; + } + + /** Runs a build or test task now, as the commands do. */ + async execute(command: "build" | "test", root: string, extra: Partial<McppTaskDefinition> = {}): Promise<vscode.TaskExecution> { + return vscode.tasks.executeTask(this.task({ type: "mcpp", command, ...extra }, root)); + } + + dispose(): void { + this.registration.dispose(); + } +} diff --git a/vscode/src/testing.ts b/vscode/src/testing.ts new file mode 100644 index 0000000..e853f65 --- /dev/null +++ b/vscode/src/testing.ts @@ -0,0 +1,94 @@ +// mcpp's tests in VS Code's Testing view. The tests of each project come from `test/list` (mcpp +// test --list: no build), each item located at the file that holds its `main`; a run is one test +// job, filtered to the test asked for, and each `test/result` marks its item. +import * as vscode from "vscode"; + +import type { Jobs } from "./jobs"; +import { parseTestId, testId } from "./mapping"; +import type { Projects } from "./projects"; +import type { Session } from "./session"; +import type { TestResult } from "./protocol"; + +export class Testing implements vscode.Disposable { + private readonly controller = vscode.tests.createTestController("mcpp", "mcpp"); + private readonly disposables: vscode.Disposable[] = [this.controller]; + + constructor(private readonly session: Session, private readonly jobs: Jobs, private readonly projects: Projects) { + this.controller.resolveHandler = async (item) => { if (!item) await this.discover(); }; + this.controller.refreshHandler = async () => { await this.discover(); }; + this.controller.createRunProfile(session.t("Run"), vscode.TestRunProfileKind.Run, (request, token) => this.run(request, token), true); + this.disposables.push( + session.on("manifest/changed", () => void this.discover()), + session.on("result/changed", () => void this.discover()), + session.onDidStart.event(() => void this.discover()), + ); + } + + async discover(): Promise<void> { + for (const project of this.projects.all) { + let tests: { test: string; member: string; main: string }[] = []; + try { + tests = (await this.session.request<{ tests: { test: string; member: string; main: string }[] }>("test/list", { root: project.root })).tests; + } catch { + continue; + } + let group = this.controller.items.get(project.root); + if (!group) { + group = this.controller.createTestItem(project.root, project.name, vscode.Uri.file(project.root)); + this.controller.items.add(group); + } + const items = tests.map((t) => { + const item = this.controller.createTestItem(testId(project.root, t.member, t.test), t.member ? `${t.member} · ${t.test}` : t.test, + t.main ? vscode.Uri.file(t.main) : undefined); + if (t.main) item.range = new vscode.Range(0, 0, 0, 0); + return item; + }); + group.children.replace(items); + } + } + + private async run(request: vscode.TestRunRequest, token: vscode.CancellationToken): Promise<void> { + const run = this.controller.createTestRun(request); + // One job per project; a single test asked for becomes the job's filter. + const byRoot = new Map<string, vscode.TestItem[]>(); + const collect = (item: vscode.TestItem) => { + const id = parseTestId(item.id); + if (!id) { item.children.forEach(collect); return; } + if (request.exclude?.includes(item)) return; + if (!byRoot.has(id.root)) byRoot.set(id.root, []); + byRoot.get(id.root)!.push(item); + }; + if (request.include) request.include.forEach(collect); + else this.controller.items.forEach(collect); + for (const [root, items] of byRoot) { + if (token.isCancellationRequested) break; + items.forEach((i) => run.enqueued(i)); + const index = new Map(items.map((i) => [parseTestId(i.id)!.test, i])); + const filter = items.length === 1 && request.include ? parseTestId(items[0].id)!.test : undefined; + const handle = await this.jobs.start({ kind: "test", root, filter, color: true }, { + output: (text) => run.appendOutput(text.replace(/\r?\n/g, "\r\n")), + testResult: (r: TestResult) => { + const item = index.get(r.test); + if (!item) return; + const ms = r.durationMs; + if (r.status === "passed") run.passed(item, ms); + else if (r.status === "skipped") run.skipped(item); + else { + const message = new vscode.TestMessage(r.output || r.reason || r.status); + if (r.status === "errored") run.errored(item, message, ms); else run.failed(item, message, ms); + } + }, + }); + const cancel = token.onCancellationRequested(() => void handle.cancel()); + const done = await handle.done; + cancel.dispose(); + if (done.status !== "ok" && done.status !== "failed") + for (const i of items) run.skipped(i); + } + run.end(); + } + + dispose(): void { + this.disposables.forEach((d) => d.dispose()); + } +} diff --git a/vscode/src/toml.ts b/vscode/src/toml.ts new file mode 100644 index 0000000..ab6f369 --- /dev/null +++ b/vscode/src/toml.ts @@ -0,0 +1,81 @@ +// Editing help for mcpp.toml and build.mcpp, answered by the backend from mcpp's own key registry +// and build-program directives (toml/complete, toml/hover, toml/symbols, buildscript/complete). +// Text analysis only: no mcpp process runs, so it works in an untrusted workspace too. Whether the +// manifest is valid is mcpp's to say (diagnostics.ts). +import * as path from "node:path"; +import * as vscode from "vscode"; + +import type { Session } from "./session"; + +interface Item { + label: string; + kind?: string; + detail?: string; + documentation?: string; + insertText?: string; + snippet?: boolean; + range?: { start: { line: number; character: number }; end: { line: number; character: number } }; +} + +const KINDS: Record<string, vscode.CompletionItemKind> = { + section: vscode.CompletionItemKind.Module, + table: vscode.CompletionItemKind.Module, + key: vscode.CompletionItemKind.Property, + value: vscode.CompletionItemKind.Value, + enum: vscode.CompletionItemKind.EnumMember, + function: vscode.CompletionItemKind.Function, + template: vscode.CompletionItemKind.Snippet, + snippet: vscode.CompletionItemKind.Snippet, +}; + +function toItem(i: Item): vscode.CompletionItem { + const item = new vscode.CompletionItem(i.label, KINDS[i.kind ?? "key"] ?? vscode.CompletionItemKind.Text); + item.detail = i.detail; + if (i.documentation) item.documentation = new vscode.MarkdownString(i.documentation); + if (i.insertText) item.insertText = i.snippet ? new vscode.SnippetString(i.insertText) : i.insertText; + if (i.range) item.range = new vscode.Range(i.range.start.line, i.range.start.character, i.range.end.line, i.range.end.character); + return item; +} + +export function registerToml(context: vscode.ExtensionContext, session: Session): void { + const enabled = (key: string) => vscode.workspace.getConfiguration().get<boolean>(key) ?? true; + const params = (doc: vscode.TextDocument, pos: vscode.Position) => ({ text: doc.getText(), line: pos.line, character: pos.character }); + context.subscriptions.push( + vscode.languages.registerCompletionItemProvider({ language: "mcpp-toml" }, { + async provideCompletionItems(doc, pos) { + if (!enabled("mcpp.toml.completion")) return []; + const r = await session.request<{ items: Item[] }>("toml/complete", params(doc, pos)).catch(() => ({ items: [] as Item[] })); + return r.items.map(toItem); + }, + }, "[", ".", "=", "\"", " "), + vscode.languages.registerHoverProvider({ language: "mcpp-toml" }, { + async provideHover(doc, pos) { + if (!enabled("mcpp.toml.hover")) return undefined; + const r = await session.request<{ contents: string } | null>("toml/hover", params(doc, pos)).catch(() => null); + return r ? new vscode.Hover(new vscode.MarkdownString(r.contents)) : undefined; + }, + }), + vscode.languages.registerDocumentSymbolProvider({ language: "mcpp-toml" }, { + async provideDocumentSymbols(doc) { + if (!enabled("mcpp.toml.navigation")) return []; + type Sym = { name: string; kind: string; line: number; children?: Sym[] }; + const r = await session.request<Sym[]>("toml/symbols", { text: doc.getText() }).catch(() => [] as Sym[]); + const convert = (s: Sym): vscode.DocumentSymbol => { + const line = doc.lineAt(Math.min(s.line, doc.lineCount - 1)).range; + const sym = new vscode.DocumentSymbol(s.name, "", s.kind === "table" ? vscode.SymbolKind.Namespace : vscode.SymbolKind.Property, line, line); + sym.children = (s.children ?? []).map(convert); + return sym; + }; + return r.map(convert); + }, + }), + // build.mcpp is C++ (mcppls answers it); only `mcpp::` directives are completed here. + vscode.languages.registerCompletionItemProvider({ language: "cpp", pattern: "**/build.mcpp" }, { + async provideCompletionItems(doc, pos) { + if (!enabled("mcpp.buildScript.intelligence") || path.basename(doc.fileName) !== "build.mcpp") return []; + const r = await session.request<{ items: Item[] }>("buildscript/complete", params(doc, pos)).catch(() => ({ items: [] as Item[] })); + return r.items.map(toItem); + }, + }, ":"), + ); +} diff --git a/vscode/syntaxes/mcpp-modules.tmLanguage.json b/vscode/syntaxes/mcpp-modules.tmLanguage.json new file mode 100644 index 0000000..39bd45d --- /dev/null +++ b/vscode/syntaxes/mcpp-modules.tmLanguage.json @@ -0,0 +1,72 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "mcpp C++ Modules", + "scopeName": "source.cpp.mcpp-modules", + "injectionSelector": "L:source.cpp", + "patterns": [ + { + "include": "#module-declaration" + }, + { + "include": "#import-declaration" + } + ], + "repository": { + "module-declaration": { + "match": "^\\s*(?:(export)\\s+)?(module)\\b\\s*(?:([A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*)(?:\\s*(:)\\s*([A-Za-z_][A-Za-z0-9_]*))?|(:)\\s*([A-Za-z_][A-Za-z0-9_]*))?(?:\\s*;)?", + "captures": { + "1": { + "name": "keyword.control.export.cpp" + }, + "2": { + "name": "keyword.control.module.cpp" + }, + "3": { + "name": "entity.name.namespace.module.cpp" + }, + "4": { + "name": "punctuation.separator.module-partition.cpp" + }, + "5": { + "name": "entity.name.namespace.module.partition.cpp" + }, + "6": { + "name": "punctuation.separator.module-partition.cpp" + }, + "7": { + "name": "entity.name.namespace.module.partition.cpp" + } + } + }, + "import-declaration": { + "match": "^\\s*(?:(export)\\s+)?(import)\\b\\s*(?:(:)([A-Za-z_][A-Za-z0-9_]*)|([A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*(?::[A-Za-z_][A-Za-z0-9_]*)?)|(<[^>]+>)|(\\\"[^\\\"]+\\\"))(?:\\s*;)?", + "captures": { + "1": { + "name": "keyword.control.export.cpp" + }, + "2": { + "name": "keyword.control.import.cpp" + }, + "3": { + "name": "punctuation.separator.module-partition.cpp" + }, + "4": { + "name": "entity.name.namespace.module.partition.cpp" + }, + "5": { + "name": "entity.name.namespace.module.cpp" + }, + "6": { + "name": "string.quoted.other.header.cpp" + }, + "7": { + "name": "string.quoted.double.header.cpp" + } + } + }, + "module-name": { + "match": "\\b[A-Za-z_][A-Za-z0-9_]*(?:\\.[A-Za-z_][A-Za-z0-9_]*)*(?::[A-Za-z_][A-Za-z0-9_]*)?\\b", + "name": "entity.name.namespace.module.cpp" + } + } +} diff --git a/vscode/syntaxes/mcpp-toml.tmLanguage.json b/vscode/syntaxes/mcpp-toml.tmLanguage.json new file mode 100644 index 0000000..e0df854 --- /dev/null +++ b/vscode/syntaxes/mcpp-toml.tmLanguage.json @@ -0,0 +1,116 @@ +{ + "$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json", + "name": "mcpp TOML", + "scopeName": "source.toml.mcpp", + "patterns": [ + { + "include": "#comment" + }, + { + "include": "#table" + }, + { + "include": "#key" + }, + { + "include": "#string" + }, + { + "include": "#datetime" + }, + { + "include": "#number" + }, + { + "include": "#boolean" + }, + { + "include": "#punctuation" + } + ], + "repository": { + "comment": { + "match": "#.*$", + "name": "comment.line.number-sign.toml" + }, + "table": { + "match": "^\\s*(\\[\\[?)([^\\]\\r\\n]+?)(\\]\\]?)\\s*(?=#|$)", + "captures": { + "1": { + "name": "punctuation.definition.table.begin.toml" + }, + "2": { + "name": "entity.name.section.toml" + }, + "3": { + "name": "punctuation.definition.table.end.toml" + } + } + }, + "key": { + "match": "^\\s*((?:[A-Za-z0-9_-]+|\"[^\"]+\"|'[^']+')(?:\\s*\\.\\s*(?:[A-Za-z0-9_-]+|\"[^\"]+\"|'[^']+'))*)\\s*(=)", + "captures": { + "1": { + "name": "variable.other.key.toml" + }, + "2": { + "name": "keyword.operator.assignment.toml" + } + } + }, + "string": { + "patterns": [ + { + "begin": "\"\"\"", + "end": "\"\"\"", + "name": "string.quoted.triple.basic.toml", + "patterns": [ + { + "include": "#escape" + } + ] + }, + { + "begin": "'''", + "end": "'''", + "name": "string.quoted.triple.literal.toml" + }, + { + "begin": "\"", + "end": "\"", + "name": "string.quoted.double.toml", + "patterns": [ + { + "include": "#escape" + } + ] + }, + { + "begin": "'", + "end": "'", + "name": "string.quoted.single.toml" + } + ] + }, + "escape": { + "match": "\\\\(?:[btnfr\"\\\\]|u[0-9A-Fa-f]{4}|U[0-9A-Fa-f]{8})", + "name": "constant.character.escape.toml" + }, + "datetime": { + "match": "(?<![A-Za-z0-9_-])(?:\\d{4}-\\d{2}-\\d{2}(?:[Tt ]\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?(?:[Zz]|[+-]\\d{2}:\\d{2})?)?|\\d{2}:\\d{2}:\\d{2}(?:\\.\\d+)?)(?![A-Za-z0-9_-])", + "name": "constant.other.datetime.toml" + }, + "number": { + "match": "(?<![A-Za-z0-9_-])[-+]?(?:0x[0-9A-Fa-f](?:_?[0-9A-Fa-f])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*|(?:\\d(?:_?\\d)*)(?:\\.\\d(?:_?\\d)*)?(?:[eE][-+]?\\d(?:_?\\d)*)?|inf|nan)(?![A-Za-z0-9_-])", + "name": "constant.numeric.toml" + }, + "boolean": { + "match": "(?<![A-Za-z0-9_-])(?:true|false)(?![A-Za-z0-9_-])", + "name": "constant.language.boolean.toml" + }, + "punctuation": { + "match": "[\\[\\]{},.]", + "name": "punctuation.separator.toml" + } + } +} diff --git a/vscode/test/e2e/runTest.ts b/vscode/test/e2e/runTest.ts new file mode 100644 index 0000000..b0a84c4 --- /dev/null +++ b/vscode/test/e2e/runTest.ts @@ -0,0 +1,46 @@ +// The extension in a real VS Code: the staged extension (dist/extension, what `vsce package` packs), +// a workspace holding one project, the backend this repository built, and the mock mcpp answering +// it from the golden fixtures. MCPP_E2E_CODE runs an installed VS Code instead of downloading one. +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; + +import { runTests } from "@vscode/test-electron"; + +import { built, repo } from "../unit/harness"; + +async function main(): Promise<void> { + const backend = built("mcpp-ide"), mock = built("mcpp-ide-mock-mcpp"); + if (!backend || !mock) throw new Error("build the backend first (mcpp build)"); + const temp = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-e2e-")); + const workspace = path.join(temp, "app"); + fs.mkdirSync(path.join(workspace, "src"), { recursive: true }); + fs.mkdirSync(path.join(workspace, "tests"), { recursive: true }); + fs.writeFileSync(path.join(workspace, "mcpp.toml"), '[package]\nname = "app"\nversion = "0.1.0"\n'); + fs.writeFileSync(path.join(workspace, "src", "main.cpp"), "int main() { return 0; }\n"); + fs.writeFileSync(path.join(workspace, "tests", "test_smoke.cpp"), "int main() { return 0; }\n"); + const user = path.join(temp, "user-data", "User"); + fs.mkdirSync(user, { recursive: true }); + fs.writeFileSync(path.join(user, "settings.json"), JSON.stringify({ + "mcpp.ide.backendPath": backend, + "mcpp.path": mock, + "security.workspace.trust.enabled": false, + })); + const executable = process.env.MCPP_E2E_CODE; + const extensionDevelopmentPath = path.join(repo, "vscode", "dist", "extension"); + await runTests({ + ...(executable ? { vscodeExecutablePath: executable } : { version: "1.91.0" }), + extensionDevelopmentPath, + extensionTestsPath: path.join(repo, "vscode", "out", "test", "e2e", "suite", "index.js"), + launchArgs: [workspace, "--user-data-dir", path.join(temp, "user-data"), "--extensions-dir", path.join(temp, "extensions"), + "--disable-gpu", "--disable-workspace-trust", "--skip-welcome", "--skip-release-notes", + // No display (a container, an agent's shell): Chromium's headless platform. + ...(process.env.MCPP_E2E_HEADLESS ? ["--ozone-platform=headless"] : [])], + extensionTestsEnv: { MCPPIDE_E2E_WORKSPACE: workspace }, + }); +} + +main().catch((e) => { + console.error(e); + process.exit(1); +}); diff --git a/vscode/test/e2e/suite/index.ts b/vscode/test/e2e/suite/index.ts new file mode 100644 index 0000000..931d998 --- /dev/null +++ b/vscode/test/e2e/suite/index.ts @@ -0,0 +1,83 @@ +// The extension host's tests: each case below, in order, failing at the first assertion. +import * as assert from "node:assert/strict"; +import * as fs from "node:fs"; +import * as path from "node:path"; +import * as vscode from "vscode"; + +import type { McppApi } from "../../../src/extension"; + +const workspace = process.env.MCPPIDE_E2E_WORKSPACE!; +const until = async (what: string, ok: () => boolean | Promise<boolean>, ms = 30_000) => { + const end = Date.now() + ms; + while (Date.now() < end) { + if (await ok()) return; + await new Promise((r) => setTimeout(r, 100)); + } + throw new Error(`timed out: ${what}`); +}; + +const cases: [string, (api: McppApi) => Promise<void>][] = [ + ["every declared command is registered", async () => { + const declared = vscode.extensions.getExtension("mcpp-community.mcpp-vscode")!.packageJSON.contributes.commands as { command: string }[]; + const known = new Set(await vscode.commands.getCommands(true)); + for (const c of declared) assert.ok(known.has(c.command), c.command); + assert.ok(declared.length > 40); + }], + ["the backend found the project and mcpp", async (api) => { + const info = api.session.info!; + assert.equal(info.projects.length, 1); + assert.equal(info.projects[0].name, "app"); + assert.equal(info.mcpp?.contract, true); + await until("the current project", async () => (await api.projects.resolve())?.name === "app"); + }], + ["a build runs as a task and ends ok", async (api) => { + const finished = new Promise<{ status: string }>((resolve) => { const d = api.session.on("job/finished", (p) => { d.dispose(); resolve(p); }); }); + await vscode.commands.executeCommand("mcpp.build"); + assert.equal((await finished).status, "ok"); + await until("the task to end", () => vscode.tasks.taskExecutions.length === 0); + }], + ["a failed build puts mcpp's diagnostic on the source", async (api) => { + fs.writeFileSync(path.join(workspace, ".mock-mcpp-fail"), "build"); + const finished = new Promise<{ status: string }>((resolve) => { const d = api.session.on("job/finished", (p) => { d.dispose(); resolve(p); }); }); + await vscode.commands.executeCommand("mcpp.build"); + assert.equal((await finished).status, "failed"); + fs.rmSync(path.join(workspace, ".mock-mcpp-fail")); + await until("the task to end", () => vscode.tasks.taskExecutions.length === 0); + await until("a diagnostic", () => vscode.languages.getDiagnostics().some(([uri, ds]) => uri.fsPath.endsWith("main.cpp") && ds.some((d) => d.source === "mcpp"))); + }], + ["the targets panel opens", async () => { + await vscode.commands.executeCommand("mcpp.showTargets"); + await until("a panel tab", () => vscode.window.tabGroups.all.some((g) => g.tabs.some((t) => t.label.startsWith("mcpp: ")))); + }], + ["mcpp.toml is completed from mcpp's key registry", async () => { + const doc = await vscode.workspace.openTextDocument(path.join(workspace, "mcpp.toml")); + await vscode.window.showTextDocument(doc); + assert.equal(doc.languageId, "mcpp-toml"); + const list = await vscode.commands.executeCommand<vscode.CompletionList>("vscode.executeCompletionItemProvider", doc.uri, new vscode.Position(3, 0)); + const labels = list.items.map((i) => (typeof i.label === "string" ? i.label : i.label.label)); + assert.ok(labels.includes("description"), `a key of [package]: ${labels.slice(0, 10).join(", ")}`); + }], + ["run starts the program in a terminal", async () => { + await vscode.commands.executeCommand("mcpp.run"); + await until("the run terminal", () => vscode.window.terminals.some((t) => t.name.startsWith("mcpp run:"))); + }], +]; + +export async function run(): Promise<void> { + const ext = vscode.extensions.getExtension<McppApi>("mcpp-community.mcpp-vscode"); + assert.ok(ext, "the extension is installed"); + const api = await ext.activate(); + // The notifications, for the log of a failing run. + api.session.on("*", ({ method, params }: { method: string; params: { jobId?: string; status?: string } }) => { + if (method.startsWith("job/started") || method.startsWith("job/finished")) console.log(` ${method} ${params.jobId ?? ""} ${params.status ?? ""}`); + }); + for (const [name, fn] of cases) { + try { + await fn(api); + console.log(`ok ${name}`); + } catch (e) { + console.log(`FAIL ${name}`); + throw e; + } + } +} diff --git a/vscode/test/unit/client.test.ts b/vscode/test/unit/client.test.ts new file mode 100644 index 0000000..4f5d8da --- /dev/null +++ b/vscode/test/unit/client.test.ts @@ -0,0 +1,38 @@ +// The wire against the real backend: frames split anywhere reassemble; `initialize` over the mock +// mcpp finds the project; a build's notifications arrive and end in job/finished. +import * as assert from "node:assert/strict"; +import { test } from "node:test"; + +import { Backend, encode, FrameReader } from "../../src/backend/client"; +import { built, project } from "./harness"; + +test("frames reassemble whatever the chunking", () => { + const all = Buffer.concat([Buffer.from("Junk: 1\r\n\r\n"), encode({ a: 1 }), encode({ b: "é" })]); + const r = new FrameReader(); + const bodies: string[] = []; + for (let i = 0; i < all.length; i++) bodies.push(...r.feed(all.subarray(i, i + 1))); + assert.deepEqual(bodies.map((b) => JSON.parse(b)), [{ a: 1 }, { b: "é" }]); +}); + +test("a session over the mock mcpp", async (t) => { + const backend = built("mcpp-ide"), mock = built("mcpp-ide-mock-mcpp"); + if (!backend || !mock) { t.skip("build the backend first (mcpp build)"); return; } + const root = project(); + const b = new Backend({ program: backend }); + const init = await b.request<{ projects: { root: string }[]; mcpp: { contract: boolean } }>("initialize", { + editor: "vscode", settings: { "mcpp.path": mock }, workspaceFolders: [root], + }); + assert.equal(init.projects.length, 1); + assert.equal(init.mcpp.contract, true); + const seen: string[] = []; + b.notifications.on("*", (method: string) => seen.push(method)); + const finished = new Promise((resolve) => b.notifications.on("job/finished", resolve)); + const { jobId } = await b.request<{ jobId: string }>("job/start", { kind: "build", root }); + assert.match(jobId, /^job-/); + const done = (await finished) as { status: string }; + assert.equal(done.status, "ok"); + for (const m of ["job/started", "job/plan", "job/progress", "job/artifact"]) assert.ok(seen.includes(m), m); + await assert.rejects(b.request("no/such/method"), /unknown method/); + await b.stop(); + assert.equal(b.running, false); +}); diff --git a/vscode/test/unit/harness.ts b/vscode/test/unit/harness.ts new file mode 100644 index 0000000..6c15e09 --- /dev/null +++ b/vscode/test/unit/harness.ts @@ -0,0 +1,36 @@ +// What the unit tests share: the repository, the programs its build produced (the backend and the +// mock mcpp, newest first), and a project directory the mock answers for. +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; + +export const repo = path.resolve(__dirname, "..", "..", "..", ".."); + +export function built(name: string): string | undefined { + const exe = process.platform === "win32" ? `${name}.exe` : name; + if (name === "mcpp-ide" && process.env.MCPP_IDE_BACKEND) return process.env.MCPP_IDE_BACKEND; + let best: string | undefined; + let bestTime = 0; + const walk = (dir: string, depth: number) => { + if (depth > 4) return; + let entries: fs.Dirent[] = []; + try { entries = fs.readdirSync(dir, { withFileTypes: true }); } catch { return; } + for (const e of entries) { + const p = path.join(dir, e.name); + if (e.isDirectory()) walk(p, depth + 1); + else if (e.name === exe && path.basename(dir) === "bin") { + const t = fs.statSync(p).mtimeMs; + if (t > bestTime) { best = p; bestTime = t; } + } + } + }; + walk(path.join(repo, "target"), 0); + return best; +} + +export function project(): string { + const root = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-vscode-")); + fs.mkdirSync(path.join(root, "src")); + fs.writeFileSync(path.join(root, "mcpp.toml"), '[package]\nname = "app"\nversion = "0.1.0"\n'); + return root; +} diff --git a/vscode/test/unit/locate.test.ts b/vscode/test/unit/locate.test.ts new file mode 100644 index 0000000..7bc92aa --- /dev/null +++ b/vscode/test/unit/locate.test.ts @@ -0,0 +1,35 @@ +// Where the backend and mcppls are found. +import * as assert from "node:assert/strict"; +import * as fs from "node:fs"; +import * as os from "node:os"; +import * as path from "node:path"; +import { test } from "node:test"; + +import { locateBackend, onPath, platformDir } from "../../src/backend/locate"; +import { mcpplsCandidates } from "../../src/backend/mcppls"; + +test("the configured path wins, then the bundled program", () => { + const ext = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-ext-")); + assert.deepEqual(locateBackend({ configured: "/x/mcpp-ide", extensionRoot: ext }), { program: "/x/mcpp-ide", source: "setting" }); + const dir = path.join(ext, "bin", platformDir("linux", "x64")); + fs.mkdirSync(dir, { recursive: true }); + fs.writeFileSync(path.join(dir, "mcpp-ide"), ""); + const found = locateBackend({ extensionRoot: ext, platform: "linux", arch: "x64", env: { PATH: "" }, home: "/nonexistent" }); + assert.equal(found?.source, "bundled"); + assert.equal(platformDir("win32", "x64"), "win32-x64"); +}); + +test("PATH lookup appends .exe on Windows", () => { + const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-path-")); + fs.writeFileSync(path.join(dir, "mcpp-ide.exe"), ""); + assert.equal(onPath("mcpp-ide", { PATH: dir }, "win32"), path.join(dir, "mcpp-ide.exe")); + assert.equal(onPath("mcpp-ide", { PATH: dir }, "linux"), undefined); +}); + +test("mcppls: the extension's payload names its server", () => { + const ext = fs.mkdtempSync(path.join(os.tmpdir(), "mcppls-ext-")); + fs.mkdirSync(path.join(ext, "payload")); + fs.writeFileSync(path.join(ext, "payload", "payload.json"), JSON.stringify({ server: { path: "bin/mcppls" } })); + assert.deepEqual(mcpplsCandidates(ext, {}), [path.join(ext, "payload", "bin", "mcppls")]); + assert.deepEqual(mcpplsCandidates(undefined, { MCPPLS_SERVER: "/s/mcppls" }), ["/s/mcppls"]); +}); diff --git a/vscode/test/unit/mapping.test.ts b/vscode/test/unit/mapping.test.ts new file mode 100644 index 0000000..c6ef829 --- /dev/null +++ b/vscode/test/unit/mapping.test.ts @@ -0,0 +1,27 @@ +// The protocol's values in VS Code's terms. +import * as assert from "node:assert/strict"; +import { test } from "node:test"; + +import { availableDebuggers, format, parseTestId, severityOf, testId, zeroBased } from "../../src/mapping"; + +test("positions are 1-based in mcpp and 0-based in VS Code", () => { + assert.deepEqual(zeroBased({ line: 1, column: 21 }), { line: 0, character: 20 }); + assert.deepEqual(zeroBased(undefined), { line: 0, character: 0 }); +}); + +test("severities", () => { + assert.equal(severityOf({ severity: "error" }), "error"); + assert.equal(severityOf({ severity: "note" }), "hint"); + assert.equal(severityOf({ severity: "info" }), "information"); +}); + +test("a test's identity round-trips, roots with :: included", () => { + const id = testId("/a::b", "m", "t"); + assert.deepEqual(parseTestId(id), { root: "/a::b", member: "m", test: "t" }); + assert.equal(parseTestId("x"), undefined); +}); + +test("the debuggers present, in order of preference", () => { + assert.deepEqual(availableDebuggers((id) => id === "ms-vscode.cpptools" || id === "vadimcn.vscode-lldb"), ["lldb", "cppdbg"]); + assert.equal(format("{0} and {1}", ["a", 2]), "a and 2"); +}); diff --git a/vscode/tsconfig.json b/vscode/tsconfig.json new file mode 100644 index 0000000..21db1ce --- /dev/null +++ b/vscode/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "Node", + "lib": ["ES2022"], + "rootDir": ".", + "outDir": "out", + "strict": true, + "esModuleInterop": true, + "resolveJsonModule": true, + "forceConsistentCasingInFileNames": true, + "skipLibCheck": true, + "sourceMap": true + }, + "include": ["src/**/*.ts", "test/**/*.ts"] +} From fe3726d7ab4e2348d85409d8178306e55a90a650 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 03:13:16 +0900 Subject: [PATCH 05/30] jetbrains: mcpp-clion 0.1.0 for CLion 2025.2 and later MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The plugin starts the backend per project and maps its protocol onto the IDE: the "mcpp" run configuration type (run in a PTY console, test into the IDE's test tree through TeamCity messages, build as a backend job whose stop cancels it), a ▶ beside main (the project's program, or the test whose main it is), debugging under CLion's own GDB or LLDB, console links to file:line:column, and the mcpp tool window hosting the shared panels in JCEF. The Tools | mcpp menu and the message bundles are generated from spec/ (mcpp-ide-dev gen jetbrains), included by plugin.xml. It depends on the mcppls CLion plugin and registers no language service; at startup it points out a root compile_commands.json an earlier mcpp left, which would let CLion's compilation-database support take the project over. The Marketplace refuses a product name in a plugin's name, so the plugin is named "mcpp"; its ID and archive keep mcpp-clion. Only public platform API: the Plugin Verifier passes against CLion 2025.2 and 2026.2.3. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- jetbrains/README.md | 34 +++ jetbrains/build.gradle.kts | 127 +++++++++ jetbrains/gradle.properties | 11 + jetbrains/settings.gradle.kts | 8 + .../mcppcommunity/mcppclion/McppIcons.kt | 8 + .../mcppcommunity/mcppclion/McppSession.kt | 180 +++++++++++++ .../mcppcommunity/mcppclion/McppStartup.kt | 40 +++ .../mcppclion/actions/Dispatch.kt | 246 ++++++++++++++++++ .../mcppclion/backend/Backend.kt | 158 +++++++++++ .../mcppcommunity/mcppclion/backend/Locate.kt | 50 ++++ .../mcppclion/run/McppConsoleFilter.kt | 31 +++ .../mcppclion/run/McppDebugRunner.kt | 53 ++++ .../mcppclion/run/McppProducers.kt | 77 ++++++ .../mcppclion/run/McppRunConfiguration.kt | 112 ++++++++ .../mcppcommunity/mcppclion/run/McppStates.kt | 242 +++++++++++++++++ .../mcppclion/settings/McppConfigurable.kt | 31 +++ .../mcppclion/settings/McppSettings.kt | 46 ++++ .../mcppclion/webui/McppPanels.kt | 64 +++++ .../mcppclion/webui/WebuiPanel.kt | 182 +++++++++++++ .../src/main/resources/META-INF/mcpp-jcef.xml | 2 + .../resources/META-INF/mcpp-testrunner.xml | 2 + .../src/main/resources/META-INF/plugin.xml | 49 ++++ .../main/resources/META-INF/pluginIcon.svg | 1 + jetbrains/src/main/resources/icons/mcpp.svg | 1 + .../src/main/resources/icons/mcpp_dark.svg | 1 + .../mcppcommunity/mcppclion/BackendTest.kt | 77 ++++++ 26 files changed, 1833 insertions(+) create mode 100644 jetbrains/README.md create mode 100644 jetbrains/build.gradle.kts create mode 100644 jetbrains/gradle.properties create mode 100644 jetbrains/settings.gradle.kts create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppIcons.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppSession.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppStartup.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/actions/Dispatch.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Backend.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppConsoleFilter.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppDebugRunner.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppProducers.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppRunConfiguration.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppStates.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/settings/McppConfigurable.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/settings/McppSettings.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/webui/McppPanels.kt create mode 100644 jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/webui/WebuiPanel.kt create mode 100644 jetbrains/src/main/resources/META-INF/mcpp-jcef.xml create mode 100644 jetbrains/src/main/resources/META-INF/mcpp-testrunner.xml create mode 100644 jetbrains/src/main/resources/META-INF/plugin.xml create mode 100644 jetbrains/src/main/resources/META-INF/pluginIcon.svg create mode 100644 jetbrains/src/main/resources/icons/mcpp.svg create mode 100644 jetbrains/src/main/resources/icons/mcpp_dark.svg create mode 100644 jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt diff --git a/jetbrains/README.md b/jetbrains/README.md new file mode 100644 index 0000000..8b8ae0b --- /dev/null +++ b/jetbrains/README.md @@ -0,0 +1,34 @@ +# mcpp-clion + +mcpp's project features in CLion 2025.2 and later, over the mcpp-ide backend: + +- the **mcpp** run configuration type: run (the program in a PTY console), test (the IDE's test + tree) or build, for a target and a profile; a ▶ beside `main` runs the project, or the test whose + `main` it is; +- **debugging** under CLion's own GDB or LLDB (the default toolchain's); an ok image runs under + `okrun`, whose images reach GDB through the JIT interface; +- **console links** to `file:line:column`; +- the **mcpp tool window**: project, libraries, cache, targets and platforms, and the graphs, pack + and settings panels (Settings | Tools | mcpp); +- the **Tools | mcpp** menu, generated from `spec/commands.json`. + +Language features of C++ files come from the mcppls CLion plugin, which this plugin depends on; it +registers no language service. + +## Build + +```bash +xlings install gradle # Gradle and its JDK +mcpp build # in the repository root: the backend and mcpp-ide-dev +gradle buildPlugin # build/distributions/mcpp-clion-<version>.zip +gradle verifyPlugin # CLion 2025.2 and the version in gradle.properties +``` + +`MCPP_IDE_BACKENDS` names a directory laid out `<platform>/mcpp-ide[.exe]` (`linux-x64`, +`linux-arm64`, `darwin-arm64`, `win32-x64`) whose programs the archive carries; without it the +plugin finds the backend through `mcpp.ide.backendPath`, xlings or PATH. + +## Tests + +`gradle test` runs the wire's tests, and a session over the mock mcpp when `MCPP_IDE_BACKEND` and +`MCPP_IDE_MOCK_MCPP` name the programs `mcpp build` produced. diff --git a/jetbrains/build.gradle.kts b/jetbrains/build.gradle.kts new file mode 100644 index 0000000..e05e725 --- /dev/null +++ b/jetbrains/build.gradle.kts @@ -0,0 +1,127 @@ +// mcpp-clion: mcpp's project features in CLion -- run configurations, the test tree, debugging, the +// console's links, and the shared panels (../webui) -- over the mcpp-ide backend (`mcpp-ide serve`). +// +// Language features are mcppls's: this plugin depends on the mcppls CLion plugin and registers no +// language service. The declarations generated from ../spec (actions, message bundles) are written +// by the backend's `mcpp-ide-dev gen jetbrains` before the resources are processed; nothing +// generated is in the repository. +// +// Gradle and the JDK it runs on come from `xim:gradle`. +import org.jetbrains.intellij.platform.gradle.IntelliJPlatformType +import org.jetbrains.intellij.platform.gradle.TestFrameworkType +import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode + +plugins { + id("java") + id("org.jetbrains.kotlin.jvm") version "2.4.0" + id("org.jetbrains.intellij.platform") version "2.19.0" +} + +group = "io.github.mcpp-community" +version = providers.gradleProperty("pluginVersion").get() + +repositories { + mavenCentral() + intellijPlatform { defaultRepositories() } +} + +// The mcppls CLion plugin, from its release: the dependency the sandbox, the tests and the verifier +// load beside this plugin. Fetched once, when the build is configured, because the platform's +// dependency resolution reads it then. +val mcpplsVersion = providers.gradleProperty("mcpplsPluginVersion").get() +val mcpplsArchive: File = layout.buildDirectory.file("mcppls/mcppls-clion-$mcpplsVersion.zip").get().asFile +if (!mcpplsArchive.exists()) { + mcpplsArchive.parentFile.mkdirs() + val url = "https://github.com/Sunrisepeak/mcpp-language-server/releases/download/v$mcpplsVersion/mcppls-clion-$mcpplsVersion.zip" + val partial = File(mcpplsArchive.path + ".part") + uri(url).toURL().openStream().use { input -> partial.outputStream().use { input.copyTo(it) } } + partial.renameTo(mcpplsArchive) +} + +dependencies { + intellijPlatform { + create(providers.gradleProperty("platformType").get(), providers.gradleProperty("platformVersion").get()) + bundledPlugin("com.intellij.clion") + // CLion's debugger (CidrLocalDebugProcess, the GDB and LLDB drivers). + bundledPlugin("com.intellij.nativeDebug") + // The panels' browser and the test tree: a plugin and a module of their own since 2026.1. + bundledPlugin("com.intellij.modules.jcef") + bundledModule("intellij.platform.smRunner") + bundledModule("intellij.platform.testRunner") + localPlugin(mcpplsArchive.absolutePath) + testFramework(TestFrameworkType.Platform) + } + testImplementation("junit:junit:4.13.2") + testImplementation("org.opentest4j:opentest4j:1.3.0") +} + +kotlin { + jvmToolchain(21) + // Built against the current CLion, run on 2025.2 too: no platform default method is copied + // into this plugin's classes as a call to `super` that 2025.2 lacks. + compilerOptions { jvmDefault = JvmDefaultMode.NO_COMPATIBILITY } +} + +// ../spec -> the generated resources: the actions (META-INF/mcpp-actions.xml, included by plugin.xml) +// and the message bundles. `mcpp-ide-dev` is the backend package's program; MCPP_IDE_DEV names a +// built one, else `mcpp run` builds it. +val generatedResources = layout.buildDirectory.dir("generated/mcpp-ide") +val generateDeclarations = tasks.register<Exec>("generateDeclarations") { + val out = generatedResources.get().asFile + inputs.dir(rootDir.resolve("../spec")) + outputs.dir(out) + workingDir = rootDir.resolve("..") + val dev = System.getenv("MCPP_IDE_DEV") + if (dev != null) commandLine(dev, "gen", "jetbrains", "--out", out.absolutePath) + else commandLine("mcpp", "run", "mcpp-ide-dev", "--", "gen", "jetbrains", "--out", out.absolutePath) +} +// ../webui, as it is: the panels JCEF loads. +val copyWebui = tasks.register<Sync>("copyWebui") { + from(rootDir.resolve("../webui")) { exclude("tests/**", "tsconfig.json", "js/types.d.ts") } + into(layout.buildDirectory.dir("generated/webui/webui")) +} +sourceSets { + main { + resources.srcDir(generatedResources) + resources.srcDir(layout.buildDirectory.dir("generated/webui")) + } +} +tasks.processResources { dependsOn(generateDeclarations, copyWebui) } + +// The backend programs the plugin carries, one per system (`bin/<platform>/mcpp-ide[.exe]`), from +// MCPP_IDE_BACKENDS (a directory laid out that way). Without it the plugin finds the backend on PATH +// or through xlings. +val backends = providers.environmentVariable("MCPP_IDE_BACKENDS") +tasks.prepareSandbox { + if (backends.isPresent) from(backends.get()) { into("${intellijPlatform.projectName.get()}/bin") } +} + +intellijPlatform { + // The settings page is the shared web panel: there is nothing for the settings search to index, + // and the index is built by starting an IDE, which a machine without a display cannot. + buildSearchableOptions = false + pluginConfiguration { + id = "io.github.mcpp-community.mcpp-clion" + name = "mcpp" + version = providers.gradleProperty("pluginVersion") + ideaVersion { + sinceBuild = "252" + untilBuild = provider { null } + } + } + // `gradle verifyPlugin`: the oldest CLion the plugin claims and the one it is built on. + pluginVerification { + ides { + create(IntelliJPlatformType.CLion, "2025.2") + create(IntelliJPlatformType.CLion, providers.gradleProperty("platformVersion").get()) + } + } +} + +tasks.test { + systemProperty("mcppide.fixtures", rootDir.resolve("../protocol/fixtures").absolutePath) + providers.environmentVariable("MCPP_IDE_BACKEND").orNull?.let { systemProperty("mcppide.backend", it) } + providers.environmentVariable("MCPP_IDE_MOCK_MCPP").orNull?.let { systemProperty("mcppide.mockMcpp", it) } + systemProperty("patch.engine.backend.freeze.timeout", "0") + testLogging { showStandardStreams = true; events("passed", "failed", "skipped") } +} diff --git a/jetbrains/gradle.properties b/jetbrains/gradle.properties new file mode 100644 index 0000000..b4ba3b3 --- /dev/null +++ b/jetbrains/gradle.properties @@ -0,0 +1,11 @@ +# The CLion build the plugin is compiled and tested against. sinceBuild in build.gradle.kts gates +# where it installs (2025.2 and later); the verifier checks both ends. +platformType = CL +platformVersion = 2026.2.3 +pluginVersion = 0.1.0 +# The mcppls CLion plugin this one depends on (<depends>io.github.sunrisepeak.mcppls</depends>): +# the release archive, fetched for the sandbox, the tests and the verifier. +mcpplsPluginVersion = 0.0.17 +org.gradle.jvmargs = -Xmx2g +# The IDE ships the Kotlin standard library; a plugin bundles no second copy. +kotlin.stdlib.default.dependency = false diff --git a/jetbrains/settings.gradle.kts b/jetbrains/settings.gradle.kts new file mode 100644 index 0000000..cf57639 --- /dev/null +++ b/jetbrains/settings.gradle.kts @@ -0,0 +1,8 @@ +// The Kotlin compiler needs the JDK build.gradle.kts asks for, not whichever one Gradle runs on: +// `xim:gradle` brings a newer JDK than the IntelliJ platform's. The resolver makes the toolchain +// declaration mean what it says. +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "1.0.0" +} + +rootProject.name = "mcpp-clion" diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppIcons.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppIcons.kt new file mode 100644 index 0000000..d039457 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppIcons.kt @@ -0,0 +1,8 @@ +package io.github.mcppcommunity.mcppclion + +import com.intellij.openapi.util.IconLoader +import javax.swing.Icon + +object McppIcons { + @JvmField val Logo: Icon = IconLoader.getIcon("/icons/mcpp.svg", McppIcons::class.java) +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppSession.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppSession.kt new file mode 100644 index 0000000..e65e263 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppSession.kt @@ -0,0 +1,180 @@ +// The session with the backend for one project: started when an mcpp project opens, given the +// IDE's settings, trust, language and the project's directory, kept current as they change, and +// restarted once when it ends. Everything else in the plugin reaches the backend through it. +package io.github.mcppcommunity.mcppclion + +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.intellij.DynamicBundle +import com.intellij.ide.impl.isTrusted +import com.intellij.notification.NotificationGroupManager +import com.intellij.notification.NotificationType +import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ApplicationInfo +import com.intellij.openapi.components.Service +import com.intellij.openapi.diagnostic.logger +import com.intellij.openapi.project.Project +import io.github.mcppcommunity.mcppclion.backend.Backend +import io.github.mcppcommunity.mcppclion.backend.Locate +import io.github.mcppcommunity.mcppclion.settings.McppSettings +import java.io.File +import java.util.concurrent.CompletableFuture +import java.util.concurrent.CopyOnWriteArrayList + +@Service(Service.Level.PROJECT) +class McppSession(private val project: Project) : Disposable { + private val log = logger<McppSession>() + @Volatile private var backend: Backend? = null + @Volatile private var started: CompletableFuture<JsonObject>? = null + @Volatile var initialized: JsonObject? = null; private set + @Volatile private var bundle: Map<String, String> = emptyMap() + @Volatile var commands: List<JsonObject> = emptyList(); private set + private val listeners = CopyOnWriteArrayList<Pair<String, (JsonElement) -> Unit>>() + private var restarts = 0 + + init { + project.messageBus.connect(this).subscribe(McppSettings.CHANGED, McppSettings.Listener { key -> + if (key == "mcpp.ide.backendPath") restart() else pushSettings() + }) + on("manifest/changed") { p -> p.asJsonObject["root"]?.asString?.let { refreshTests(it) } } + } + + val root: String? get() = projects().firstOrNull()?.get("root")?.asString ?: project.basePath?.takeIf { File(it, "mcpp.toml").isFile } + + fun projects(): List<JsonObject> = initialized?.getAsJsonArray("projects")?.map { it.asJsonObject } ?: emptyList() + + /** A runtime string in the session's language. */ + fun t(key: String, vararg args: Any?): String { + var text = bundle[key] ?: key + args.forEachIndexed { i, a -> text = text.replace("{$i}", a.toString()) } + return text + } + + val strings: Map<String, String> get() = bundle + + fun on(method: String, listener: (JsonElement) -> Unit): () -> Unit { + val entry = method to listener + listeners += entry + return { listeners -= entry } + } + + /** The plugin's directory: the parent of the lib/ holding this class's jar. */ + private fun pluginRoot(): File? = pluginDirectory() + + /** + * The servers to ask first. The mcppls CLion plugin starts mcppls from PATH or from the payload its + * `--install` puts in the user data directory, which the backend looks at itself; MCPPLS_SERVER + * names another. + */ + private fun mcpplsCandidates(): JsonArray = JsonArray().apply { System.getenv("MCPPLS_SERVER")?.let { add(it) } } + + fun start(): CompletableFuture<JsonObject> { + started?.let { if (backend?.running == true || !it.isDone) return it } + val future = CompletableFuture<JsonObject>() + started = future + val configured = if (project.isTrusted()) McppSettings.get().string("mcpp.ide.backendPath") else "" + val located = Locate.backend(configured, pluginRoot()) + if (located == null) { + notify(t("The mcpp-ide backend was not found. Install it with `xlings install mcpp-ide`, or set mcpp.ide.backendPath."), NotificationType.ERROR) + future.completeExceptionally(IllegalStateException("mcpp-ide was not found")) + return future + } + log.info("mcpp-ide: starting ${located.program} (${located.source})") + val b = Backend(listOf(located.program.path, "serve")) { line -> log.info("[backend] $line") } + backend = b + b.on("*") { method, params -> listeners.filter { it.first == method || it.first == "*" }.forEach { (m, fn) -> + runCatching { fn(if (m == "*") JsonObject().apply { addProperty("method", method); add("params", params) } else params) } + } } + b.exited.thenAccept { code -> if (backend === b) onExit(code) } + val params = JsonObject().apply { + add("client", JsonObject().apply { addProperty("name", ApplicationInfo.getInstance().versionName); addProperty("version", ApplicationInfo.getInstance().fullVersion) }) + addProperty("editor", "jetbrains") + addProperty("locale", DynamicBundle.getLocale().toLanguageTag()) + addProperty("trusted", project.isTrusted()) + add("settings", McppSettings.get().values()) + add("workspaceFolders", JsonArray().apply { project.basePath?.let { add(it) } }) + add("languageService", JsonObject().apply { add("candidates", mcpplsCandidates()) }) + } + b.request("initialize", params).thenCompose { init -> + initialized = init.asJsonObject + b.request("i18n/bundle") + }.thenCompose { strings -> + bundle = strings.asJsonObject.entrySet().associate { it.key to it.value.asString } + b.request("commands/list", JsonObject().apply { addProperty("editor", "jetbrains") }) + }.whenComplete { table, error -> + if (error != null) { future.completeExceptionally(error); return@whenComplete } + commands = table.asJsonObject.getAsJsonArray("commands").map { it.asJsonObject } + future.complete(initialized!!) + } + return future + } + + private fun onExit(code: Int) { + log.info("mcpp-ide: the backend ended ($code)") + backend = null + if (restarts++ < 1) { start(); return } + notify(t("The mcpp-ide backend ended."), NotificationType.ERROR) + } + + fun restart() { + val old = backend + backend = null + started = null + restarts = 0 + old?.close() + start() + } + + fun request(method: String, params: JsonElement = JsonObject()): CompletableFuture<JsonElement> = + start().thenCompose { backend?.request(method, params) ?: CompletableFuture.failedFuture(IllegalStateException(t("the mcpp-ide backend is not running"))) } + + // The tests of each project by the file holding their `main` (mcpp test --list), for the gutter + // and the run configurations from context, which must not wait for mcpp. + private val testMains = java.util.concurrent.ConcurrentHashMap<String, Map<String, String>>() + + /** The test whose `main` is `path`, from what is known; asks again in the background when nothing is. */ + fun testForFile(root: String, path: String): String? { + val known = testMains[root] + if (known == null) refreshTests(root) + return known?.get(File(path).canonicalPath) + } + + fun refreshTests(root: String) { + request("test/list", JsonObject().apply { addProperty("root", root) }).thenAccept { r -> + testMains[root] = r.asJsonObject.getAsJsonArray("tests").map { it.asJsonObject } + .filter { it["main"]?.asString?.isNotEmpty() == true } + .associate { File(it["main"].asString).canonicalPath to it["test"].asString } + } + } + + fun pushSettings() { + val b = backend ?: return + b.request("settings/update", JsonObject().apply { + add("settings", McppSettings.get().values()) + addProperty("trusted", project.isTrusted()) + addProperty("locale", DynamicBundle.getLocale().toLanguageTag()) + }) + } + + fun notify(message: String, type: NotificationType = NotificationType.INFORMATION) { + NotificationGroupManager.getInstance().getNotificationGroup("mcpp").createNotification("mcpp", message, type).notify(project) + } + + override fun dispose() { + val b = backend + backend = null + b?.close() + } + + companion object { + /** <plugin>/lib/<jar> -> <plugin>, from where this class was loaded. */ + fun pluginDirectory(): File? = runCatching { + File(McppSession::class.java.protectionDomain.codeSource.location.toURI()).parentFile?.parentFile + }.getOrNull() + + const val PLUGIN_ID = "io.github.mcpp-community.mcpp-clion" + const val MCPPLS_PLUGIN_ID = "io.github.sunrisepeak.mcppls" + fun get(project: Project): McppSession = project.getService(McppSession::class.java) + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppStartup.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppStartup.kt new file mode 100644 index 0000000..a6b9802 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppStartup.kt @@ -0,0 +1,40 @@ +// When an mcpp project opens: the session starts; the language service is reported when it is not +// what mcpp projects need; and a compile_commands.json an earlier mcpp left at the root, which would +// let CLion's compilation-database support take the project over from mcppls, is pointed out. +package io.github.mcppcommunity.mcppclion + +import com.intellij.notification.NotificationAction +import com.intellij.notification.NotificationGroupManager +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project +import com.intellij.openapi.startup.ProjectActivity +import io.github.mcppcommunity.mcppclion.actions.Dispatch +import java.io.File + +class McppStartup : ProjectActivity { + override suspend fun execute(project: Project) { + val base = project.basePath ?: return + if (!File(base, "mcpp.toml").isFile) return + val session = McppSession.get(project) + session.start().thenAccept { init -> + init.get("languageService")?.takeIf { it.isJsonObject }?.asJsonObject?.let { ls -> + if (ls["state"].asString == "ok") return@let + val n = NotificationGroupManager.getInstance().getNotificationGroup("mcpp") + .createNotification("mcpp", ls["message"].asString, NotificationType.WARNING) + ls.getAsJsonArray("actions").forEach { a -> + n.addAction(NotificationAction.createSimpleExpiring(a.asJsonObject["title"].asString) { Dispatch.languageServiceAction(project, a.asJsonObject["id"].asString) }) + } + n.notify(project) + } + session.root?.let { session.refreshTests(it) } + } + val stale = File(base, "compile_commands.json") + if (stale.isFile) { + NotificationGroupManager.getInstance().getNotificationGroup("mcpp").createNotification("mcpp", + session.t("compile_commands.json at the project root was written by an earlier mcpp. CLion may open the project as a compilation database instead of leaving its C++ to mcppls; mcpp now keeps the database under target/."), + NotificationType.WARNING) + .addAction(NotificationAction.createSimpleExpiring(session.t("Remove it")) { stale.delete() }) + .notify(project) + } + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/actions/Dispatch.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/actions/Dispatch.kt new file mode 100644 index 0000000..7afd5a6 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/actions/Dispatch.kt @@ -0,0 +1,246 @@ +// The command table's actions in the IDE: every action of the mcpp menu (generated from +// spec/commands.json) is one McppCommandAction, which looks its row up in the backend's table and +// does what the row's `action` says, in the IDE's own terms (run configurations, dialogs, panels). +package io.github.mcppcommunity.mcppclion.actions + +import com.google.gson.JsonObject +import com.intellij.execution.ProgramRunnerUtil +import com.intellij.execution.RunManager +import com.intellij.execution.executors.DefaultDebugExecutor +import com.intellij.execution.executors.DefaultRunExecutor +import com.intellij.ide.BrowserUtil +import com.intellij.ide.impl.ProjectUtil +import com.intellij.notification.NotificationAction +import com.intellij.notification.NotificationGroupManager +import com.intellij.notification.NotificationType +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.fileChooser.FileChooser +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory +import com.intellij.openapi.options.ShowSettingsUtil +import com.intellij.openapi.project.DumbAwareAction +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.ui.popup.JBPopupFactory +import com.intellij.openapi.ui.popup.PopupStep +import com.intellij.openapi.ui.popup.util.BaseListPopupStep +import io.github.mcppcommunity.mcppclion.McppSession +import io.github.mcppcommunity.mcppclion.run.McppRunConfiguration +import io.github.mcppcommunity.mcppclion.run.McppRunConfigurationType +import io.github.mcppcommunity.mcppclion.settings.McppSettings +import io.github.mcppcommunity.mcppclion.webui.McppPanels +import java.io.File +import java.nio.file.Paths + +class McppCommandAction : DumbAwareAction() { + override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT + + override fun update(e: AnActionEvent) { + val project = e.project + e.presentation.isEnabledAndVisible = project != null + if (project == null) return + val id = e.actionManager.getId(this) ?: return + val needsProject = id in setOf("mcpp.build", "mcpp.run", "mcpp.debug", "mcpp.test", "mcpp.clean", "mcpp.pack", "mcpp.cleanProjectArtifacts") + if (needsProject) e.presentation.isEnabled = McppSession.get(project).root != null + } + + override fun actionPerformed(e: AnActionEvent) { + val project = e.project ?: return + val id = e.actionManager.getId(this) ?: return + Dispatch.run(project, id, JsonObject()) + } +} + +object Dispatch { + fun run(project: Project, command: String, args: JsonObject) { + val session = McppSession.get(project) + session.start().whenComplete { _, error -> + ApplicationManager.getApplication().invokeLater { + if (error != null) { session.notify(session.t("mcpp: {0}", (error.cause ?: error).message ?: ""), NotificationType.ERROR); return@invokeLater } + val entry = session.commands.firstOrNull { it["id"].asString == command } + if (entry == null) { session.notify(session.t("unknown command {0}", command), NotificationType.ERROR); return@invokeLater } + perform(project, entry["action"].asJsonObject, args) + } + } + } + + private fun configuration(project: Project, command: String, args: JsonObject) { + val session = McppSession.get(project) + val root = args["root"]?.asString ?: session.root ?: return + val manager = RunManager.getInstance(project) + val name = "mcpp $command ${File(root).name}" + (args["filter"]?.asString?.let { " $it" } ?: "") + val settings = manager.findConfigurationByName(name) ?: manager.createConfiguration(name, McppRunConfigurationType.Factory(McppRunConfigurationType())).also { + manager.addConfiguration(it) + } + val c = settings.configuration as McppRunConfiguration + c.options.command = if (command == "debug") "run" else command + c.options.root = root + args["filter"]?.asString?.let { c.options.filter = it } + args["bin"]?.asString?.let { c.options.bin = it } + manager.selectedConfiguration = settings + val executor = if (command == "debug") DefaultDebugExecutor.getDebugExecutorInstance() else DefaultRunExecutor.getRunExecutorInstance() + ProgramRunnerUtil.executeConfiguration(settings, executor) + } + + fun perform(project: Project, action: JsonObject, args: JsonObject) { + val session = McppSession.get(project) + fun t(key: String, vararg a: Any?) = session.t(key, *a) + val inner = args["args"]?.takeIf { it.isJsonObject }?.asJsonObject ?: JsonObject() + inner.entrySet().forEach { (k, v) -> if (!args.has(k)) args.add(k, v) } + when (action["kind"].asString) { + "job" -> configuration(project, if (action["job"]?.asString == "test") "test" else "build", args) + "run" -> configuration(project, "run", args) + "debug" -> configuration(project, "debug", args) + "cache" -> cleanup(project, action["plan"].asString) + "panel" -> McppPanels.show(project, action["panel"].asString, JsonObject().apply { + action["graph"]?.let { add("graph", it) } + args["id"]?.let { add("id", it) } + }) + "cancel" -> session.request("job/list").thenAccept { list -> + list.asJsonArray.forEach { j -> session.request("job/cancel", JsonObject().apply { add("jobId", j.asJsonObject["id"]) }) } + } + "selectTarget" -> selectTarget(project) + "installToolchain" -> { + val spec = Messages.showInputDialog(project, "gcc@16.1.0, llvm@23.1.3", t("Install an mcpp toolchain"), null) ?: return + job(project, "toolchains/install", JsonObject().apply { addProperty("spec", spec) }) + } + "selectDefaultToolchain" -> selectDefaultToolchain(project) + "newProject" -> newProject(project) + "selfCheck" -> session.request("selfCheck").thenAccept { r -> + val text = r.asJsonObject.getAsJsonArray("checks").joinToString("\n") { c -> "${c.asJsonObject["status"].asString.padEnd(8)} ${c.asJsonObject["message"].asString}" } + ApplicationManager.getApplication().invokeLater { Messages.showInfoMessage(project, text, t("Environment Self-check")) } + } + "languageService" -> languageService(project) + "rpc" -> job(project, action["method"].asString, JsonObject().apply { session.root?.let { addProperty("root", it) } }) + else -> session.notify(t("This command is not available in this IDE."), NotificationType.INFORMATION) + } + } + + /** A job whose narration is not a console's: its end is a notification. */ + private fun job(project: Project, method: String, params: JsonObject) { + val session = McppSession.get(project) + session.request(method, params).thenAccept { r -> + val id = r.asJsonObject["jobId"]?.asString ?: return@thenAccept + lateinit var off: () -> Unit + off = session.on("job/finished") { p -> + if (p.asJsonObject["jobId"]?.asString != id) return@on + off() + val status = p.asJsonObject["status"]?.asString ?: "failed" + session.notify(session.t("mcpp {0}: {1}", method.substringBefore('/'), status), if (status == "ok") NotificationType.INFORMATION else NotificationType.ERROR) + } + } + } + + /** plan -> the IDE's confirmation at the plan's level -> apply. */ + fun cleanup(project: Project, actionName: String) { + val session = McppSession.get(project) + fun t(key: String, vararg a: Any?) = session.t(key, *a) + session.request("cache/plan", JsonObject().apply { addProperty("action", actionName); session.root?.let { addProperty("root", it) } }).thenAccept { r -> + val plan = r.asJsonObject + ApplicationManager.getApplication().invokeLater { + if (plan["refusedUntrusted"]?.asBoolean == true) { session.notify(t("this action needs a trusted workspace"), NotificationType.WARNING); return@invokeLater } + val confirmation = JsonObject() + if (plan["level"].asInt > 0) { + val preview = plan["preview"]?.takeIf { it.isJsonObject }?.asJsonObject + val previewText = when { + preview == null -> "" + preview["source"]?.asString == "mcpp" -> preview["text"]?.asString ?: "" + else -> t("About {0} would be freed ({1} entries).", preview["bytesText"]?.asString ?: "", preview["count"]?.asString ?: "0") + } + val detail = listOf(plan["detail"].asString, previewText).filter { it.isNotBlank() }.joinToString("\n\n") + if (Messages.showOkCancelDialog(project, detail, plan["title"].asString, t("Continue"), Messages.getCancelButton(), Messages.getWarningIcon()) != Messages.OK) return@invokeLater + confirmation.addProperty("confirmed", true) + confirmation.addProperty("previewShown", preview != null) + if (plan["acknowledge"]?.asBoolean == true) { + val ack = t("I understand this affects every mcpp project on this machine") + if (Messages.showOkCancelDialog(project, ack, plan["title"].asString, ack, Messages.getCancelButton(), Messages.getWarningIcon()) != Messages.OK) return@invokeLater + confirmation.addProperty("acknowledged", true) + } + } + job(project, "cache/apply", JsonObject().apply { + addProperty("action", actionName); add("confirmation", confirmation); session.root?.let { addProperty("root", it) } + }) + } + } + } + + private fun selectTarget(project: Project) { + val session = McppSession.get(project) + session.request("targets/list", JsonObject().apply { session.root?.let { addProperty("root", it) } }).thenAccept { r -> + val rows = r.asJsonObject.getAsJsonArray("rows").map { it.asJsonObject } + ApplicationManager.getApplication().invokeLater { + val step = object : BaseListPopupStep<JsonObject>(session.t("Select the build target"), rows) { + override fun getTextFor(row: JsonObject): String { + val platform = row["platformText"]?.asString?.takeIf { it.isNotEmpty() }?.let { " · $it" } ?: "" + return (if (row["selected"].asBoolean) "✓ " else "") + row["target"].asString + platform + } + override fun onChosen(row: JsonObject, finalChoice: Boolean): PopupStep<*>? { + McppSettings.get().set("mcpp.build.target", com.google.gson.JsonPrimitive(if (row["host"].asBoolean) "" else row["target"].asString)) + return FINAL_CHOICE + } + } + JBPopupFactory.getInstance().createListPopup(step).showCenteredInCurrentWindow(project) + } + } + } + + private fun selectDefaultToolchain(project: Project) { + val session = McppSession.get(project) + session.request("toolchains/list").thenAccept { r -> + val o = r.asJsonObject + val rows = o.getAsJsonArray("rows").map { it.asJsonObject }.filter { it["target"].asString == o["host"].asString && it["spec"].asString.isNotEmpty() } + ApplicationManager.getApplication().invokeLater { + val step = object : BaseListPopupStep<JsonObject>(session.t("Choose the mcpp global default toolchain"), rows) { + override fun getTextFor(row: JsonObject): String = (if (row["default"].asBoolean) "✓ " else "") + row["spec"].asString + " (" + row["status"].asString + ")" + override fun onChosen(row: JsonObject, finalChoice: Boolean): PopupStep<*>? { + session.request("toolchains/setDefault", JsonObject().apply { add("spec", row["spec"]) }) + return FINAL_CHOICE + } + } + JBPopupFactory.getInstance().createListPopup(step).showCenteredInCurrentWindow(project) + } + } + } + + private fun newProject(project: Project) { + val session = McppSession.get(project) + val folder = FileChooser.chooseFile(FileChooserDescriptorFactory.createSingleFolderDescriptor(), project, null) ?: return + val name = Messages.showInputDialog(project, session.t("The project's name, which is also its directory"), session.t("New mcpp project (1/2)"), null) ?: return + session.request("project/new", JsonObject().apply { addProperty("parent", folder.path); addProperty("name", name) }).thenAccept { r -> + val id = r.asJsonObject["jobId"].asString + val created = r.asJsonObject["root"].asString + lateinit var off: () -> Unit + off = session.on("job/finished") { p -> + if (p.asJsonObject["jobId"]?.asString != id) return@on + off() + if (p.asJsonObject["status"]?.asString == "ok") + ApplicationManager.getApplication().invokeLater { ProjectUtil.openOrImport(Paths.get(created), project, false) } + else session.notify(session.t("mcpp new {0}: {1}", name, p.asJsonObject["status"]?.asString ?: "failed"), NotificationType.ERROR) + } + } + } + + fun languageServiceAction(project: Project, id: String) { + // The mcppls CLion plugin: its page on the Marketplace when it is listed there, else its releases. + if (id == "install" || id == "update") { + ShowSettingsUtil.getInstance().showSettingsDialog(project, "Plugins") + BrowserUtil.browse("https://github.com/Sunrisepeak/mcpp-language-server/releases") + } + } + + private fun languageService(project: Project) { + val session = McppSession.get(project) + session.request("languageService/status").thenAccept { r -> + val s = r.asJsonObject + val ok = s["state"].asString == "ok" + val n = NotificationGroupManager.getInstance().getNotificationGroup("mcpp") + .createNotification("mcpp", s["message"].asString, if (ok) NotificationType.INFORMATION else NotificationType.WARNING) + s.getAsJsonArray("actions").forEach { a -> + val o = a.asJsonObject + n.addAction(NotificationAction.createSimpleExpiring(o["title"].asString) { languageServiceAction(project, o["id"].asString) }) + } + n.notify(project) + } + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Backend.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Backend.kt new file mode 100644 index 0000000..5288b05 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Backend.kt @@ -0,0 +1,158 @@ +// The backend's wire, as the plugin speaks it: `mcpp-ide serve` as a child process, JSON-RPC 2.0 +// framed as the LSP base protocol on its standard streams. Requests answer futures; notifications +// go to the listeners of their method ("*" receives every one). +package io.github.mcppcommunity.mcppclion.backend + +import com.google.gson.JsonElement +import com.google.gson.JsonNull +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import java.io.ByteArrayOutputStream +import java.io.InputStream +import java.io.OutputStream +import java.nio.charset.StandardCharsets +import java.util.concurrent.CompletableFuture +import java.util.concurrent.ConcurrentHashMap +import java.util.concurrent.CopyOnWriteArrayList +import java.util.concurrent.TimeUnit +import java.util.concurrent.atomic.AtomicInteger + +class BackendError(val method: String, val code: Int, message: String, val data: JsonElement?) : RuntimeException(message) + +/** Splits a byte stream into the bodies of Content-Length frames. */ +class FrameReader { + private val buffer = ByteArrayOutputStream() + + fun feed(bytes: ByteArray, length: Int = bytes.size): List<String> { + buffer.write(bytes, 0, length) + val out = mutableListOf<String>() + while (true) { + val all = buffer.toByteArray() + val headerEnd = indexOf(all, "\r\n\r\n".toByteArray()) + if (headerEnd < 0) break + val headers = String(all, 0, headerEnd, StandardCharsets.US_ASCII) + val match = Regex("content-length:\\s*(\\d+)", RegexOption.IGNORE_CASE).find(headers) + val start = headerEnd + 4 + if (match == null) { reset(all, start); continue } + val n = match.groupValues[1].toInt() + if (all.size < start + n) break + out += String(all, start, n, StandardCharsets.UTF_8) + reset(all, start + n) + } + return out + } + + private fun reset(all: ByteArray, from: Int) { + buffer.reset() + buffer.write(all, from, all.size - from) + } + + private fun indexOf(hay: ByteArray, needle: ByteArray): Int { + outer@ for (i in 0..hay.size - needle.size) { + for (j in needle.indices) if (hay[i + j] != needle[j]) continue@outer + return i + } + return -1 + } +} + +fun encode(message: JsonObject): ByteArray { + val body = message.toString().toByteArray(StandardCharsets.UTF_8) + return "Content-Length: ${body.size}\r\n\r\n".toByteArray(StandardCharsets.US_ASCII) + body +} + +class Backend(command: List<String>, private val log: (String) -> Unit = {}) : AutoCloseable { + private val process: Process = ProcessBuilder(command).redirectErrorStream(false).start() + private val input: OutputStream = process.outputStream + private val pending = ConcurrentHashMap<Int, Pair<String, CompletableFuture<JsonElement>>>() + private val listeners = ConcurrentHashMap<String, CopyOnWriteArrayList<(String, JsonElement) -> Unit>>() + private val nextId = AtomicInteger(1) + private val writeLock = Any() + + val running: Boolean get() = process.isAlive + + /** The exit status, once the process has ended. */ + val exited = CompletableFuture<Int>() + + init { + thread("mcpp-ide stdout") { read(process.inputStream) } + thread("mcpp-ide stderr") { process.errorStream.bufferedReader().forEachLine(log) } + thread("mcpp-ide exit") { + process.waitFor() + val ended = BackendError("", -32099, "the mcpp-ide backend ended", null) + pending.values.forEach { it.second.completeExceptionally(ended) } + pending.clear() + exited.complete(process.exitValue()) + } + } + + private fun thread(name: String, body: () -> Unit) = Thread(body, name).apply { isDaemon = true; start() } + + private fun read(stream: InputStream) { + val reader = FrameReader() + val chunk = ByteArray(65536) + while (true) { + val n = try { stream.read(chunk) } catch (_: Exception) { -1 } + if (n < 0) break + for (body in reader.feed(chunk, n)) dispatch(body) + } + } + + private fun dispatch(body: String) { + val message = try { JsonParser.parseString(body).asJsonObject } catch (_: Exception) { return } + val id = message.get("id") + if (id != null && !id.isJsonNull && (message.has("result") || message.has("error"))) { + val (method, future) = pending.remove(id.asInt) ?: return + if (message.has("error")) { + val e = message.getAsJsonObject("error") + future.completeExceptionally(BackendError(method, e.get("code")?.asInt ?: -32603, e.get("message")?.asString ?: "failed", e.get("data"))) + } else future.complete(message.get("result") ?: JsonNull.INSTANCE) + return + } + val method = message.get("method")?.asString ?: return + val params = message.get("params") ?: JsonObject() + listeners[method]?.forEach { runCatching { it(method, params) }.onFailure { e -> log("$method: ${e.message}") } } + listeners["*"]?.forEach { runCatching { it(method, params) } } + } + + fun request(method: String, params: JsonElement = JsonObject()): CompletableFuture<JsonElement> { + val future = CompletableFuture<JsonElement>() + if (!process.isAlive) { + future.completeExceptionally(BackendError(method, -32099, "the mcpp-ide backend is not running", null)) + return future + } + val id = nextId.getAndIncrement() + pending[id] = method to future + send(JsonObject().apply { addProperty("jsonrpc", "2.0"); addProperty("id", id); addProperty("method", method); add("params", params) }) + return future + } + + fun notify(method: String, params: JsonElement = JsonObject()) { + if (process.isAlive) send(JsonObject().apply { addProperty("jsonrpc", "2.0"); addProperty("method", method); add("params", params) }) + } + + private fun send(message: JsonObject) { + synchronized(writeLock) { + try { + input.write(encode(message)) + input.flush() + } catch (e: Exception) { + log("write failed: ${e.message}") + } + } + } + + fun on(method: String, listener: (String, JsonElement) -> Unit): () -> Unit { + val list = listeners.computeIfAbsent(method) { CopyOnWriteArrayList() } + list += listener + return { list -= listener } + } + + override fun close() { + if (!process.isAlive) return + runCatching { request("shutdown").get(2, TimeUnit.SECONDS) } + notify("exit") + runCatching { input.close() } + if (!process.waitFor(3, TimeUnit.SECONDS)) process.destroy() + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt new file mode 100644 index 0000000..34923d6 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt @@ -0,0 +1,50 @@ +// Where the backend is: the configured path, the one the plugin carries for this system +// (`bin/<platform>/mcpp-ide[.exe]`), the one xlings installed, then PATH. +package io.github.mcppcommunity.mcppclion.backend + +import java.io.File + +object Locate { + val windows: Boolean = System.getProperty("os.name").lowercase().startsWith("windows") + + /** "linux-x64", "darwin-arm64", "win32-x64": the same directory names the VS Code extension uses. */ + fun platformDir(os: String = System.getProperty("os.name"), arch: String = System.getProperty("os.arch")): String { + val o = os.lowercase() + val system = when { + o.startsWith("windows") -> "win32" + o.startsWith("mac") || o.contains("darwin") -> "darwin" + else -> "linux" + } + val machine = when (arch.lowercase()) { + "amd64", "x86_64" -> "x64" + "aarch64", "arm64" -> "arm64" + else -> arch.lowercase() + } + return "$system-$machine" + } + + private fun exe(name: String) = if (windows) "$name.exe" else name + + fun onPath(name: String, path: String? = System.getenv("PATH")): File? = + (path ?: "").split(File.pathSeparatorChar).filter { it.isNotEmpty() } + .map { File(it, exe(name)) }.firstOrNull { it.isFile && it.canExecute() } + + data class Located(val program: File, val source: String) + + fun backend(configured: String, pluginRoot: File?): Located? { + if (configured.isNotBlank()) return Located(File(configured.trim()), "setting") + pluginRoot?.let { root -> + val bundled = File(root, "bin/${platformDir()}/${exe("mcpp-ide")}") + if (bundled.isFile) { + if (!bundled.canExecute()) bundled.setExecutable(true) + return Located(bundled, "bundled") + } + } + val home = System.getProperty("user.home") + listOfNotNull(System.getenv("XLINGS_HOME")?.let { File(it, "subos/current/bin/${exe("mcpp-ide")}") }, + File(home, ".xlings/subos/current/bin/${exe("mcpp-ide")}"), + File(home, ".xlings/subos/default/bin/${exe("mcpp-ide")}")) + .firstOrNull { it.isFile }?.let { return Located(it, "xlings") } + return onPath("mcpp-ide")?.let { Located(it, "PATH") } + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppConsoleFilter.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppConsoleFilter.kt new file mode 100644 index 0000000..34f6c91 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppConsoleFilter.kt @@ -0,0 +1,31 @@ +// Links in the console: `path:line:column:` as a compiler or mcpp prints it opens that place, a +// relative path read against the project. +package io.github.mcppcommunity.mcppclion.run + +import com.intellij.execution.filters.ConsoleFilterProvider +import com.intellij.execution.filters.Filter +import com.intellij.execution.filters.OpenFileHyperlinkInfo +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.LocalFileSystem +import java.io.File + +class McppConsoleFilterProvider : ConsoleFilterProvider { + override fun getDefaultFilters(project: Project): Array<Filter> = arrayOf(McppConsoleFilter(project)) +} + +class McppConsoleFilter(private val project: Project) : Filter { + private val location = Regex("""((?:[A-Za-z]:)?[^\s:'"()]+\.(?:cppm|cpp|cc|cxx|ixx|mpp|c|h|hpp|hxx|toml|mcpp)):(\d+)(?::(\d+))?""") + + override fun applyFilter(line: String, entireLength: Int): Filter.Result? { + val start = entireLength - line.length + val items = location.findAll(line).mapNotNull { m -> + val path = m.groupValues[1] + val file = File(path).let { if (it.isAbsolute) it else File(project.basePath ?: return@mapNotNull null, path) } + val vf = LocalFileSystem.getInstance().findFileByIoFile(file) ?: return@mapNotNull null + val lineNo = (m.groupValues[2].toIntOrNull() ?: 1) - 1 + val column = (m.groupValues[3].toIntOrNull() ?: 1) - 1 + Filter.ResultItem(start + m.range.first, start + m.range.last + 1, OpenFileHyperlinkInfo(project, vf, lineNo, column)) + }.toList() + return if (items.isEmpty()) null else Filter.Result(items) + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppDebugRunner.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppDebugRunner.kt new file mode 100644 index 0000000..6ea6daf --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppDebugRunner.kt @@ -0,0 +1,53 @@ +// Debugging an "mcpp" run configuration under CLion's own debugger (GDB or LLDB, as the default +// toolchain names it). The backend builds the program and says how it starts; the debugger starts +// exactly that. A program that runs through a runner (an ok image under okrun) is debugged as the +// runner: okrun registers each image through the GDB JIT interface, which GDB reads by default. +package io.github.mcppcommunity.mcppclion.run + +import com.intellij.execution.ExecutionException +import com.intellij.execution.configurations.RunProfile +import com.intellij.execution.configurations.RunProfileState +import com.intellij.execution.configurations.RunnerSettings +import com.intellij.execution.executors.DefaultDebugExecutor +import com.intellij.execution.filters.TextConsoleBuilderFactory +import com.intellij.execution.runners.ExecutionEnvironment +import com.intellij.execution.runners.GenericProgramRunner +import com.intellij.execution.ui.RunContentDescriptor +import com.intellij.notification.NotificationType +import com.intellij.openapi.progress.ProgressManager +import com.intellij.xdebugger.XDebugProcess +import com.intellij.xdebugger.XDebugProcessStarter +import com.intellij.xdebugger.XDebugSession +import com.intellij.xdebugger.XDebuggerManager +import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionGDBDriverConfiguration +import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionLLDBDriverConfiguration +import com.jetbrains.cidr.cpp.toolchains.CPPToolchains +import com.jetbrains.cidr.execution.TrivialRunParameters +import com.jetbrains.cidr.execution.debugger.CidrLocalDebugProcess +import io.github.mcppcommunity.mcppclion.McppSession + +class McppDebugRunner : GenericProgramRunner<RunnerSettings>() { + override fun getRunnerId(): String = "McppDebugRunner" + + override fun canRun(executorId: String, profile: RunProfile): Boolean = + executorId == DefaultDebugExecutor.EXECUTOR_ID && profile is McppRunConfiguration && profile.options.command == "run" + + override fun doExecute(state: RunProfileState, env: ExecutionEnvironment): RunContentDescriptor? { + val c = env.runProfile as McppRunConfiguration + val project = c.project + val session = McppSession.get(project) + val toolchain = CPPToolchains.getInstance().defaultToolchain + ?: throw ExecutionException(session.t("No toolchain is set up in Settings | Build, Execution, Deployment | Toolchains; CLion's debugger comes from one.")) + val launch = ProgressManager.getInstance().runProcessWithProgressSynchronously<com.google.gson.JsonObject, Exception>( + { launch(c).get() }, session.t("mcpp: building for the debugger…"), true, project) + val lldb = toolchain.debuggerKind.isLLDB() + if (!launch["via"].isJsonNull && lldb) + session.notify(session.t("This program runs through {0}. LLDB reads its symbols once `settings set plugin.jit-loader.gdb.enable on` is in ~/.lldbinit; GDB reads them as it is.", launch["via"].asString), NotificationType.INFORMATION) + val driver = if (lldb) CLionLLDBDriverConfiguration(project, toolchain) else CLionGDBDriverConfiguration(project, toolchain) + val parameters = TrivialRunParameters(driver, commandLine(launch, pty = false)) + return XDebuggerManager.getInstance(project).startSession(env, object : XDebugProcessStarter() { + override fun start(xs: XDebugSession): XDebugProcess = + CidrLocalDebugProcess(parameters, xs, TextConsoleBuilderFactory.getInstance().createBuilder(project)) + }).runContentDescriptor + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppProducers.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppProducers.kt new file mode 100644 index 0000000..25e3f30 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppProducers.kt @@ -0,0 +1,77 @@ +// Run configurations from context, and the ▶ beside `main`: a C++ file of an mcpp project whose +// `main` is a test's (mcpp test --list names the file) runs that test; any other `main` runs the +// project's program. Both come from the same producer, so Run and Debug are offered alike. +package io.github.mcppcommunity.mcppclion.run + +import com.intellij.execution.actions.ConfigurationContext +import com.intellij.execution.actions.LazyRunConfigurationProducer +import com.intellij.execution.configurations.ConfigurationFactory +import com.intellij.execution.configurations.ConfigurationTypeUtil +import com.intellij.execution.lineMarker.ExecutorAction +import com.intellij.execution.lineMarker.RunLineMarkerContributor +import com.intellij.icons.AllIcons +import com.intellij.openapi.util.Ref +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.psi.PsiElement +import io.github.mcppcommunity.mcppclion.McppSession +import java.io.File + +private val MAIN = Regex("""^\s*(?:export\s+)?(?:int|auto)\s+main\s*\(""") + +/** The mcpp project a file belongs to: the nearest directory above it with an mcpp.toml. */ +internal fun projectOf(file: VirtualFile?): String? { + var dir = file?.parent + while (dir != null) { + if (dir.findChild("mcpp.toml") != null) return dir.path + dir = dir.parent + } + return null +} + +/** The test a file is the `main` of (mcpp test --list), as far as the session knows; null otherwise. */ +internal fun testOf(session: McppSession, root: String, file: VirtualFile): String? = session.testForFile(root, file.path) + +class McppConfigurationProducer : LazyRunConfigurationProducer<McppRunConfiguration>() { + override fun getConfigurationFactory(): ConfigurationFactory = + ConfigurationTypeUtil.findConfigurationType(McppRunConfigurationType::class.java).configurationFactories[0] + + override fun setupConfigurationFromContext(c: McppRunConfiguration, context: ConfigurationContext, source: Ref<PsiElement>): Boolean { + val file = context.location?.virtualFile ?: return false + val root = projectOf(file) ?: return false + val text = context.psiLocation?.containingFile?.text ?: return false + if (!text.lineSequence().any { MAIN.containsMatchIn(it) }) return false + c.options.root = root + val test = testOf(McppSession.get(c.project), root, file) + if (test != null) { + c.options.command = "test" + c.options.filter = test + c.name = "mcpp test $test" + } else { + c.options.command = "run" + c.name = "mcpp run ${File(root).name}" + } + return true + } + + override fun isConfigurationFromContext(c: McppRunConfiguration, context: ConfigurationContext): Boolean { + val file = context.location?.virtualFile ?: return false + val root = projectOf(file) ?: return false + if (c.root != root) return false + val test = testOf(McppSession.get(c.project), root, file) + return if (test != null) c.options.command == "test" && c.options.filter == test else c.options.command == "run" + } +} + +/** The ▶ in the gutter beside a `main` of an mcpp project's C++ file. */ +class McppRunLineMarker : RunLineMarkerContributor() { + override fun getInfo(element: PsiElement): Info? { + if (element.firstChild != null || element.text != "main") return null + val file = element.containingFile?.virtualFile ?: return null + if (projectOf(file) == null) return null + val document = element.containingFile.viewProvider.document ?: return null + val line = document.getLineNumber(element.textOffset) + val text = document.getText(com.intellij.openapi.util.TextRange(document.getLineStartOffset(line), document.getLineEndOffset(line))) + if (!MAIN.containsMatchIn(text)) return null + return Info(AllIcons.RunConfigurations.TestState.Run, ExecutorAction.getActions(0)) { "mcpp" } + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppRunConfiguration.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppRunConfiguration.kt new file mode 100644 index 0000000..b7f4947 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppRunConfiguration.kt @@ -0,0 +1,112 @@ +// The "mcpp" run configuration type: run, test or build a project, for a target and a profile. Run +// asks the backend how the program starts (it builds first) and runs it in a PTY console; build and +// test are backend jobs whose narration the console shows; a test run fills the test tree. Debug +// runs the program under CLion's own debugger (McppDebugRunner). +package io.github.mcppcommunity.mcppclion.run + +import com.intellij.execution.Executor +import com.intellij.execution.configurations.ConfigurationFactory +import com.intellij.execution.configurations.ConfigurationTypeBase +import com.intellij.execution.configurations.RunConfiguration +import com.intellij.execution.configurations.RunConfigurationBase +import com.intellij.execution.configurations.RunConfigurationOptions +import com.intellij.execution.configurations.RunProfileState +import com.intellij.execution.runners.ExecutionEnvironment +import com.intellij.openapi.components.BaseState +import com.intellij.openapi.options.SettingsEditor +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.ComboBox +import com.intellij.ui.components.JBTextField +import com.intellij.util.ui.FormBuilder +import io.github.mcppcommunity.mcppclion.McppIcons +import javax.swing.JComponent + +class McppRunConfigurationType : ConfigurationTypeBase(ID, "mcpp", "Run, test or build an mcpp project", McppIcons.Logo) { + init { + addFactory(Factory(this)) + } + + class Factory(type: McppRunConfigurationType) : ConfigurationFactory(type) { + override fun getId(): String = ID + override fun createTemplateConfiguration(project: Project): RunConfiguration = McppRunConfiguration(project, this, "mcpp") + override fun getOptionsClass(): Class<out BaseState> = McppRunOptions::class.java + } + + companion object { + const val ID = "McppRunConfiguration" + } +} + +class McppRunOptions : RunConfigurationOptions() { + private val commandProperty = string("run").provideDelegate(this, "command") + private val targetProperty = string("").provideDelegate(this, "target") + private val profileProperty = string("").provideDelegate(this, "profile") + private val argsProperty = string("").provideDelegate(this, "args") + private val filterProperty = string("").provideDelegate(this, "filter") + private val binProperty = string("").provideDelegate(this, "bin") + private val rootProperty = string("").provideDelegate(this, "root") + + var command: String get() = commandProperty.getValue(this) ?: "run"; set(v) = commandProperty.setValue(this, v) + var target: String get() = targetProperty.getValue(this) ?: ""; set(v) = targetProperty.setValue(this, v) + var profile: String get() = profileProperty.getValue(this) ?: ""; set(v) = profileProperty.setValue(this, v) + var args: String get() = argsProperty.getValue(this) ?: ""; set(v) = argsProperty.setValue(this, v) + var filter: String get() = filterProperty.getValue(this) ?: ""; set(v) = filterProperty.setValue(this, v) + var bin: String get() = binProperty.getValue(this) ?: ""; set(v) = binProperty.setValue(this, v) + var root: String get() = rootProperty.getValue(this) ?: ""; set(v) = rootProperty.setValue(this, v) +} + +class McppRunConfiguration(project: Project, factory: ConfigurationFactory, name: String) : + RunConfigurationBase<McppRunOptions>(project, factory, name) { + + public override fun getOptions(): McppRunOptions = super.getOptions() as McppRunOptions + + /** The project directory: the configuration's own, else the IDE project's. */ + val root: String get() = options.root.ifBlank { project.basePath ?: "" } + + /** The arguments the program (run) or the test binaries receive, split as a shell would not: on spaces. */ + val programArgs: List<String> get() = options.args.split(' ').filter { it.isNotBlank() } + + override fun getConfigurationEditor(): SettingsEditor<out RunConfiguration> = Editor() + + override fun getState(executor: Executor, environment: ExecutionEnvironment): RunProfileState = when (options.command) { + "test" -> McppTestState(this, environment) + "build" -> McppJobState(this, environment) + else -> McppProgramState(this, environment) + } + + class Editor : SettingsEditor<McppRunConfiguration>() { + private val command = ComboBox(arrayOf("run", "test", "build")) + private val target = JBTextField() + private val profile = ComboBox(arrayOf("", "dev", "release")) + private val args = JBTextField() + private val filter = JBTextField() + private val bin = JBTextField() + + override fun resetEditorFrom(c: McppRunConfiguration) { + command.selectedItem = c.options.command + target.text = c.options.target + profile.selectedItem = c.options.profile + args.text = c.options.args + filter.text = c.options.filter + bin.text = c.options.bin + } + + override fun applyEditorTo(c: McppRunConfiguration) { + c.options.command = command.selectedItem as String + c.options.target = target.text.trim() + c.options.profile = profile.selectedItem as String + c.options.args = args.text + c.options.filter = filter.text.trim() + c.options.bin = bin.text.trim() + } + + override fun createEditor(): JComponent = FormBuilder.createFormBuilder() + .addLabeledComponent("Command:", command) + .addLabeledComponent("Target (empty: the mcpp.build.target setting):", target) + .addLabeledComponent("Profile (empty: the mcpp.build.profile setting):", profile) + .addLabeledComponent("Executable (run):", bin) + .addLabeledComponent("Test filter (test):", filter) + .addLabeledComponent("Arguments:", args) + .panel + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppStates.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppStates.kt new file mode 100644 index 0000000..b896a02 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/run/McppStates.kt @@ -0,0 +1,242 @@ +// What a run of an "mcpp" configuration is: a backend job (build), a backend test job feeding the +// test tree, or the program itself (run). Each is a ProcessHandler, so the console, the stop button +// and the run toolbar behave as for any other run in the IDE. +package io.github.mcppcommunity.mcppclion.run + +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.intellij.execution.DefaultExecutionResult +import com.intellij.execution.ExecutionResult +import com.intellij.execution.Executor +import com.intellij.execution.configurations.CommandLineState +import com.intellij.execution.configurations.GeneralCommandLine +import com.intellij.execution.configurations.PtyCommandLine +import com.intellij.execution.process.AnsiEscapeDecoder +import com.intellij.execution.process.KillableColoredProcessHandler +import com.intellij.execution.process.ProcessEvent +import com.intellij.execution.process.ProcessHandler +import com.intellij.execution.process.ProcessListener +import com.intellij.execution.process.ProcessOutputTypes +import com.intellij.execution.runners.ExecutionEnvironment +import com.intellij.execution.runners.ProgramRunner +import com.intellij.execution.testframework.sm.SMTestRunnerConnectionUtil +import com.intellij.execution.testframework.sm.runner.SMTRunnerConsoleProperties +import com.intellij.openapi.util.Key +import io.github.mcppcommunity.mcppclion.McppSession +import java.io.OutputStream +import java.util.concurrent.CompletableFuture + +/** The parameters every job of a configuration shares: project, target, profile. */ +internal fun jobParams(c: McppRunConfiguration, kind: String): JsonObject = JsonObject().apply { + addProperty("kind", kind) + addProperty("root", c.root) + addProperty("color", true) + if (c.options.target.isNotBlank()) addProperty("target", c.options.target) + if (c.options.profile.isNotBlank()) addProperty("profile", c.options.profile) +} + +/** + * A backend job as a process: started on `startNotify`, its narration (ANSI colours decoded) as the + * output, its end as the exit code; stopping it cancels the job, which mcpp ends cleanly. + */ +open class JobProcessHandler(protected val session: McppSession, private val params: JsonObject, private val method: String = "job/start") : + ProcessHandler(), AnsiEscapeDecoder.ColoredTextAcceptor { + private val decoder = AnsiEscapeDecoder() + @Volatile protected var jobId: String? = null + private val early = mutableListOf<Pair<String, JsonElement>>() + private val subscriptions = mutableListOf<() -> Unit>() + + override fun startNotify() { + super.startNotify() + for (m in listOf("job/output", "job/finished", "test/result", "test/summary")) + subscriptions += session.on(m) { p -> route(m, p) } + session.request(method, params).whenComplete { r, e -> + if (e != null) { + print("${(e.cause ?: e).message}\n", ProcessOutputTypes.STDERR) + finish(1) + return@whenComplete + } + val id = r.asJsonObject["jobId"].asString + val replay: List<Pair<String, JsonElement>> + synchronized(early) { jobId = id; replay = early.filter { it.second.asJsonObject["jobId"]?.asString == id }; early.clear() } + replay.forEach { (m, p) -> handle(m, p.asJsonObject) } + } + } + + private fun route(method: String, p: JsonElement) { + val o = p.asJsonObject + synchronized(early) { + if (jobId == null) { early += method to p; return } + } + if (o["jobId"]?.asString == jobId) handle(method, o) + } + + protected open fun handle(method: String, p: JsonObject) { + when (method) { + "job/output" -> print(p["text"].asString, ProcessOutputTypes.STDOUT) + "job/finished" -> { + val status = p["status"]?.asString ?: "failed" + print("\n${session.t("mcpp {0}: {1}", params["kind"]?.asString ?: "job", status)}\n", ProcessOutputTypes.SYSTEM) + finish(p["exitCode"]?.takeIf { !it.isJsonNull }?.asInt ?: if (status == "ok") 0 else 1) + } + } + } + + protected fun print(text: String, type: Key<*>) = decoder.escapeText(text.replace("\r\n", "\n"), type, this) + + override fun coloredTextAvailable(text: String, attributes: Key<*>) = notifyTextAvailable(text, attributes) + + private fun finish(code: Int) { + subscriptions.forEach { it() } + subscriptions.clear() + notifyProcessTerminated(code) + } + + override fun destroyProcessImpl() { + val id = jobId + if (id == null) { finish(130); return } + session.request("job/cancel", JsonObject().apply { addProperty("jobId", id) }) + } + + override fun detachProcessImpl() { + subscriptions.forEach { it() } + notifyProcessDetached() + } + + override fun detachIsDefault(): Boolean = false + override fun getProcessInput(): OutputStream? = null +} + +class McppJobState(private val c: McppRunConfiguration, env: ExecutionEnvironment) : CommandLineState(env) { + override fun startProcess(): ProcessHandler = JobProcessHandler(McppSession.get(c.project), jobParams(c, "build").apply { + if (c.programArgs.isNotEmpty()) add("args", JsonArray().apply { c.programArgs.forEach { add(it) } }) + }) +} + +/** + * A test job whose results fill the IDE's test tree: each `test/result` becomes the TeamCity + * service messages the test runner reads, located at the file that holds the test's `main`. + */ +class TestJobProcessHandler(session: McppSession, params: JsonObject, private val mains: Map<String, String>) : JobProcessHandler(session, params) { + private fun escape(s: String) = s.replace("|", "||").replace("'", "|'").replace("\n", "|n").replace("\r", "|r").replace("[", "|[").replace("]", "|]") + + override fun handle(method: String, p: JsonObject) { + when (method) { + "test/result" -> { + val name = escape(p["test"].asString) + val hint = mains[p["test"].asString]?.let { " locationHint='file://${escape(it)}'" } ?: "" + val out = StringBuilder("##teamcity[testStarted name='$name'$hint]\n") + val output = p["output"]?.asString ?: "" + if (output.isNotEmpty()) out.append("##teamcity[testStdOut name='$name' out='${escape(output)}']\n") + when (p["status"]?.asString) { + "passed" -> {} + "skipped" -> out.append("##teamcity[testIgnored name='$name']\n") + else -> out.append("##teamcity[testFailed name='$name' message='${escape(p["reason"]?.asString?.ifBlank { null } ?: p["status"].asString)}']\n") + } + out.append("##teamcity[testFinished name='$name' duration='${p["durationMs"]?.asLong ?: 0}']\n") + notifyTextAvailable(out.toString(), ProcessOutputTypes.STDOUT) + } + else -> super.handle(method, p) + } + } +} + +class McppTestState(private val c: McppRunConfiguration, env: ExecutionEnvironment) : CommandLineState(env) { + override fun startProcess(): ProcessHandler { + val session = McppSession.get(c.project) + val mains = runCatching { + session.request("test/list", JsonObject().apply { addProperty("root", c.root) }).get() + .asJsonObject.getAsJsonArray("tests").associate { it.asJsonObject["test"].asString to it.asJsonObject["main"].asString } + }.getOrDefault(emptyMap()) + return TestJobProcessHandler(session, jobParams(c, "test").apply { + if (c.options.filter.isNotBlank()) addProperty("filter", c.options.filter) + if (c.programArgs.isNotEmpty()) add("args", JsonArray().apply { add("--"); c.programArgs.forEach { add(it) } }) + }, mains) + } + + override fun execute(executor: Executor, runner: ProgramRunner<*>): ExecutionResult { + val handler = startProcess() + val properties = SMTRunnerConsoleProperties(c, "mcpp", executor) + val console = SMTestRunnerConnectionUtil.createAndAttachConsole("mcpp", handler, properties) + return DefaultExecutionResult(console, handler) + } +} + +/** The backend's answer to "how does the program start" for a configuration (mcpp run --print-launch). */ +internal fun launch(c: McppRunConfiguration): CompletableFuture<JsonObject> { + val session = McppSession.get(c.project) + val params = JsonObject().apply { + addProperty("root", c.root) + if (c.options.target.isNotBlank()) addProperty("target", c.options.target) + if (c.options.profile.isNotBlank()) addProperty("profile", c.options.profile) + if (c.options.bin.isNotBlank()) addProperty("bin", c.options.bin) + add("args", JsonArray().apply { c.programArgs.forEach { add(it) } }) + } + return session.request("run/launch", params).thenApply { it.asJsonObject } +} + +internal fun commandLine(l: JsonObject, pty: Boolean): GeneralCommandLine { + val argv = l.getAsJsonArray("argv").map { it.asString } + val cmd = if (pty) PtyCommandLine(argv) else GeneralCommandLine(argv) + cmd.withWorkDirectory(l["cwd"].asString) + l.getAsJsonObject("env")?.entrySet()?.forEach { (k, v) -> cmd.withEnvironment(k, v.asString) } + cmd.withParentEnvironmentType(GeneralCommandLine.ParentEnvironmentType.CONSOLE) + return cmd +} + +/** + * The program: built and described by the backend, then started in a PTY so it reads input and + * colours its output as in a terminal. The build happens before the program's own process exists, + * so this handler stands for both. + */ +class LaunchingProcessHandler(private val c: McppRunConfiguration) : ProcessHandler() { + @Volatile private var inner: ProcessHandler? = null + @Volatile private var cancelled = false + + override fun startNotify() { + super.startNotify() + val session = McppSession.get(c.project) + notifyTextAvailable("${session.t("mcpp: building…")}\n", ProcessOutputTypes.SYSTEM) + launch(c).whenComplete { l, e -> + if (e != null) { + val cause = e.cause ?: e + val narration = (cause as? io.github.mcppcommunity.mcppclion.backend.BackendError)?.data?.takeIf { it.isJsonObject } + ?.asJsonObject?.get("narration")?.asString + if (narration != null) notifyTextAvailable(narration, ProcessOutputTypes.STDERR) + notifyTextAvailable("${cause.message}\n", ProcessOutputTypes.STDERR) + notifyProcessTerminated(1) + return@whenComplete + } + if (cancelled) { notifyProcessTerminated(130); return@whenComplete } + val handler = runCatching { KillableColoredProcessHandler(commandLine(l, pty = true)) }.getOrElse { + notifyTextAvailable("${it.message}\n", ProcessOutputTypes.STDERR) + notifyProcessTerminated(1) + return@whenComplete + } + handler.addProcessListener(object : ProcessListener { + override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) = notifyTextAvailable(event.text, outputType) + override fun processTerminated(event: ProcessEvent) = notifyProcessTerminated(event.exitCode) + }) + inner = handler + handler.startNotify() + } + } + + override fun destroyProcessImpl() { + cancelled = true + inner?.destroyProcess() ?: notifyProcessTerminated(130) + } + + override fun detachProcessImpl() { + inner?.detachProcess() + notifyProcessDetached() + } + + override fun detachIsDefault(): Boolean = false + override fun getProcessInput(): OutputStream? = inner?.processInput +} + +class McppProgramState(private val c: McppRunConfiguration, env: ExecutionEnvironment) : CommandLineState(env) { + override fun startProcess(): ProcessHandler = LaunchingProcessHandler(c) +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/settings/McppConfigurable.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/settings/McppConfigurable.kt new file mode 100644 index 0000000..eaa2b73 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/settings/McppConfigurable.kt @@ -0,0 +1,31 @@ +// Settings | Tools | mcpp: the shared settings panel, the same one VS Code shows. +package io.github.mcppcommunity.mcppclion.settings + +import com.google.gson.JsonObject +import com.intellij.openapi.Disposable +import com.intellij.openapi.options.Configurable +import com.intellij.openapi.project.Project +import com.intellij.openapi.util.Disposer +import io.github.mcppcommunity.mcppclion.webui.WebuiPanel +import javax.swing.JComponent + +class McppConfigurable(private val project: Project) : Configurable { + private var disposable: Disposable? = null + + override fun getDisplayName(): String = "mcpp" + + override fun createComponent(): JComponent { + val d = Disposer.newDisposable("mcpp settings") + disposable = d + return WebuiPanel(project, "settings", JsonObject(), d).component + } + + // Every change is stored as it is made (the panel writes through the host). + override fun isModified(): Boolean = false + override fun apply() {} + + override fun disposeUIResources() { + disposable?.let { Disposer.dispose(it) } + disposable = null + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/settings/McppSettings.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/settings/McppSettings.kt new file mode 100644 index 0000000..0c0d5a3 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/settings/McppSettings.kt @@ -0,0 +1,46 @@ +// The mcpp settings of this IDE: the same keys as VS Code's (spec/settings.json), each value kept as +// JSON. What a key may hold, its default and its renames are the backend's to say; this only stores. +package io.github.mcppcommunity.mcppclion.settings + +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.util.messages.Topic + +@Service(Service.Level.APP) +@State(name = "McppIdeSettings", storages = [Storage("mcpp-ide.xml")]) +class McppSettings : PersistentStateComponent<McppSettings.State> { + class State { + var values: MutableMap<String, String> = sortedMapOf() + } + + private var state = State() + + override fun getState(): State = state + override fun loadState(s: State) { state = s } + + fun values(): JsonObject = JsonObject().also { o -> + for ((k, v) in state.values) runCatching { o.add(k, JsonParser.parseString(v)) } + } + + fun get(key: String): JsonElement? = state.values[key]?.let { runCatching { JsonParser.parseString(it) }.getOrNull() } + + fun string(key: String, default: String = ""): String = get(key)?.takeIf { it.isJsonPrimitive }?.asString ?: default + + fun set(key: String, value: JsonElement?) { + if (value == null || value.isJsonNull) state.values.remove(key) else state.values[key] = value.toString() + ApplicationManager.getApplication().messageBus.syncPublisher(CHANGED).changed(key) + } + + fun interface Listener { fun changed(key: String) } + + companion object { + val CHANGED: Topic<Listener> = Topic.create("mcpp settings", Listener::class.java) + fun get(): McppSettings = ApplicationManager.getApplication().getService(McppSettings::class.java) + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/webui/McppPanels.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/webui/McppPanels.kt new file mode 100644 index 0000000..22eee42 --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/webui/McppPanels.kt @@ -0,0 +1,64 @@ +// The panels' places in the IDE: the "mcpp" tool window holds the project, libraries, cache and +// targets panels; any other panel (a graph, pack, settings, a package's page) opens there as a tab +// of its own, which a second request for the same panel selects again. +package io.github.mcppcommunity.mcppclion.webui + +import com.google.gson.JsonObject +import com.intellij.openapi.project.DumbAware +import com.intellij.openapi.project.Project +import com.intellij.openapi.wm.ToolWindow +import com.intellij.openapi.wm.ToolWindowFactory +import com.intellij.openapi.wm.ToolWindowManager +import com.intellij.ui.content.ContentFactory +import io.github.mcppcommunity.mcppclion.McppSession +import java.io.File + +object McppPanels { + const val TOOL_WINDOW = "mcpp" + private val defaults = listOf("project", "libraries", "cache", "targets") + + fun title(session: McppSession, panel: String, params: JsonObject): String = when (panel) { + "project" -> session.t("Project") + "libraries", "library" -> params["id"]?.asString ?: session.t("Libraries") + "cache" -> session.t("Cache") + "targets" -> session.t("Targets and Platforms") + "settings" -> session.t("Settings") + "pack" -> session.t("Pack") + "graph" -> if (params["graph"]?.asString == "modules") session.t("Module graph") else session.t("Dependency graph") + else -> panel + } + + private fun key(panel: String, params: JsonObject) = "$panel:${params["graph"]?.asString ?: ""}:${params["id"]?.asString ?: ""}" + + fun add(project: Project, window: ToolWindow, panel: String, params: JsonObject, closeable: Boolean) { + val session = McppSession.get(project) + val content = ContentFactory.getInstance().createContent(null, title(session, panel, params), false) + val view = WebuiPanel(project, if (panel == "library") "libraries" else panel, params, content) + content.component = view.component + content.isCloseable = closeable + content.putUserData(KEY, key(panel, params)) + window.contentManager.addContent(content) + } + + fun show(project: Project, panel: String, params: JsonObject = JsonObject()) { + val window = ToolWindowManager.getInstance(project).getToolWindow(TOOL_WINDOW) ?: return + if (!params.has("root")) McppSession.get(project).root?.let { params.addProperty("root", it) } + val wanted = key(panel, params) + val existing = window.contentManager.contents.firstOrNull { it.getUserData(KEY) == wanted } + if (existing == null) add(project, window, panel, params, closeable = panel !in defaults) + val content = window.contentManager.contents.first { it.getUserData(KEY) == wanted } + window.contentManager.setSelectedContent(content) + window.activate(null) + } + + private val KEY = com.intellij.openapi.util.Key.create<String>("mcpp.panel") + + class Factory : ToolWindowFactory, DumbAware { + override suspend fun isApplicableAsync(project: Project): Boolean = project.basePath?.let { File(it, "mcpp.toml").isFile } ?: false + + override fun createToolWindowContent(project: Project, toolWindow: ToolWindow) { + val params = JsonObject().apply { McppSession.get(project).root?.let { addProperty("root", it) } } + for (panel in defaults) add(project, toolWindow, panel, params.deepCopy(), closeable = false) + } + } +} diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/webui/WebuiPanel.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/webui/WebuiPanel.kt new file mode 100644 index 0000000..38751fc --- /dev/null +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/webui/WebuiPanel.kt @@ -0,0 +1,182 @@ +// The shared panels (../webui) in a JCEF browser. The page speaks the backend's protocol through +// this host -- `window.mcppHostSend` (a JBCefJSQuery) out, `window.mcppHostReceive` in -- and asks +// it for what only the IDE does: open a file, confirm, store a setting, run a command. +package io.github.mcppcommunity.mcppclion.webui + +import com.google.gson.Gson +import com.google.gson.JsonElement +import com.google.gson.JsonNull +import com.google.gson.JsonObject +import com.google.gson.JsonParser +import com.intellij.ide.BrowserUtil +import com.intellij.ide.actions.RevealFileAction +import com.intellij.notification.NotificationType +import com.intellij.openapi.Disposable +import com.intellij.openapi.application.ApplicationManager +import com.intellij.openapi.application.PathManager +import com.intellij.openapi.fileEditor.OpenFileDescriptor +import com.intellij.openapi.ide.CopyPasteManager +import com.intellij.openapi.project.Project +import com.intellij.openapi.ui.Messages +import com.intellij.openapi.util.Disposer +import com.intellij.openapi.vfs.LocalFileSystem +import com.intellij.ui.JBColor +import com.intellij.ui.jcef.JBCefApp +import com.intellij.ui.jcef.JBCefBrowser +import com.intellij.ui.jcef.JBCefBrowserBase +import com.intellij.ui.jcef.JBCefJSQuery +import com.intellij.util.ui.UIUtil +import io.github.mcppcommunity.mcppclion.McppSession +import io.github.mcppcommunity.mcppclion.actions.Dispatch +import io.github.mcppcommunity.mcppclion.settings.McppSettings +import org.cef.browser.CefBrowser +import org.cef.browser.CefFrame +import org.cef.handler.CefLoadHandlerAdapter +import java.awt.Color +import java.awt.datatransfer.StringSelection +import java.io.File +import javax.swing.JComponent +import javax.swing.JLabel +import javax.swing.SwingConstants + +class WebuiPanel(private val project: Project, private val panel: String, private val params: JsonObject, parent: Disposable) : Disposable { + private val session = McppSession.get(project) + private val browser: JBCefBrowser? = if (JBCefApp.isSupported()) JBCefBrowser() else null + private val query: JBCefJSQuery? = browser?.let { JBCefJSQuery.create(it as JBCefBrowserBase) } + private val unsubscribe: () -> Unit + + val component: JComponent = browser?.component ?: JLabel(session.t("This IDE runs without JCEF; the mcpp panels need it."), SwingConstants.CENTER) + + init { + Disposer.register(parent, this) + unsubscribe = session.on("*") { message -> post(JsonObject().apply { addProperty("type", "notify"); add("method", message.asJsonObject["method"]); add("params", message.asJsonObject["params"]) }) } + if (browser != null && query != null) { + query.addHandler { text -> receive(text); null } + browser.jbCefClient.addLoadHandler(object : CefLoadHandlerAdapter() { + override fun onLoadEnd(b: CefBrowser, frame: CefFrame, status: Int) { + if (!frame.isMain) return + b.executeJavaScript("window.mcppHostSend = function (text) { ${query.inject("text")} }; window.mcppHostAttached && window.mcppHostAttached();", b.url, 0) + } + }, browser.cefBrowser) + browser.loadURL(page().toURI().toString()) + } + } + + // The page and its scripts, written once per plugin version where the browser can load them. + private fun page(): File { + // One directory per build of the plugin: its jar's name and time identify it. + val jar = runCatching { File(WebuiPanel::class.java.protectionDomain.codeSource.location.toURI()) }.getOrNull() + val version = jar?.takeIf { it.isFile }?.let { "${it.nameWithoutExtension}-${it.lastModified()}" } ?: "dev" + val dir = File(PathManager.getSystemPath(), "mcpp-clion/webui-$version") + val index = javaClass.getResource("/webui/index.html")?.readText() ?: error("webui/index.html is not in the plugin") + val files = Regex("\\{\\{base}}([\\w./-]+)").findAll(index).map { it.groupValues[1] }.toSet() + for (f in files) { + val target = File(dir, f) + if (target.isFile && version != "dev") continue + target.parentFile.mkdirs() + javaClass.getResourceAsStream("/webui/$f")?.use { input -> target.outputStream().use { input.copyTo(it) } } + } + val html = File(dir, "panel.html") + html.writeText(index.replace("{{base}}", "").replace("{{csp}}", "default-src 'self' 'unsafe-inline' file:") + .replace("{{nonce}}", "").replace("{{lang}}", com.intellij.DynamicBundle.getLocale().language)) + return html + } + + private fun css(c: Color) = "rgb(${c.red}, ${c.green}, ${c.blue})" + + private fun theme(): JsonObject = JsonObject().apply { + addProperty("--mcpp-fg", css(UIUtil.getLabelForeground())) + addProperty("--mcpp-bg", css(UIUtil.getPanelBackground())) + addProperty("--mcpp-muted", css(UIUtil.getContextHelpForeground())) + addProperty("--mcpp-border", css(JBColor.border())) + addProperty("--mcpp-card", css(UIUtil.getListBackground())) + addProperty("--mcpp-input", css(UIUtil.getTextFieldBackground())) + addProperty("--mcpp-accent", css(JBColor.namedColor("Button.default.startBackground", JBColor(0x3574F0, 0x3574F0)))) + addProperty("--mcpp-secondary", css(JBColor.namedColor("Button.startBackground", JBColor(0xEBECF0, 0x3C3F41)))) + addProperty("--mcpp-secondary-fg", css(UIUtil.getLabelForeground())) + addProperty("--mcpp-font", "\"${UIUtil.getLabelFont().family}\", system-ui, sans-serif") + addProperty("--mcpp-font-size", "${UIUtil.getLabelFont().size}px") + } + + private fun post(message: JsonObject) { + val b = browser ?: return + val js = "window.mcppHostReceive && window.mcppHostReceive(${message});" + ApplicationManager.getApplication().invokeLater { b.cefBrowser.executeJavaScript(js, b.cefBrowser.url, 0) } + } + + private fun receive(text: String) { + val m = runCatching { JsonParser.parseString(text).asJsonObject }.getOrNull() ?: return + when (m["type"]?.asString) { + "ready" -> post(JsonObject().apply { + addProperty("type", "init"); addProperty("panel", panel); add("params", params) + add("bundle", Gson().toJsonTree(session.strings)); add("theme", theme()); addProperty("editor", "jetbrains") + }) + "rpc" -> session.request(m["method"].asString, m["params"] ?: JsonObject()).whenComplete { result, error -> + if (error != null) post(JsonObject().apply { + addProperty("type", "rpcError"); add("id", m["id"]) + add("error", JsonObject().apply { addProperty("message", (error.cause ?: error).message ?: "failed") }) + }) + else post(JsonObject().apply { addProperty("type", "rpcResult"); add("id", m["id"]); add("result", result) }) + } + "host" -> ApplicationManager.getApplication().invokeLater { + val result = runCatching { host(m["action"].asString, m["params"]?.asJsonObject ?: JsonObject()) } + post(JsonObject().apply { + add("id", m["id"]) + result.onSuccess { addProperty("type", "hostResult"); add("result", it) } + result.onFailure { e -> addProperty("type", "hostError"); add("error", JsonObject().apply { addProperty("message", e.message ?: "failed") }) } + }) + } + } + } + + private fun host(action: String, p: JsonObject): JsonElement { + val settings = McppSettings.get() + return when (action) { + "settings" -> settings.values() + "setSetting" -> { settings.set(p["key"].asString, p["value"]); JsonParser.parseString("true") } + "resetSettings" -> { p.getAsJsonArray("keys").forEach { settings.set(it.asString, null) }; JsonParser.parseString("true") } + "migrateSettings" -> { + p.getAsJsonArray("renames").forEach { r -> + val o = r.asJsonObject + settings.get(o["from"].asString)?.let { v -> settings.set(o["to"].asString, v) } + } + JsonParser.parseString("true") + } + "openFile" -> { + val file = LocalFileSystem.getInstance().refreshAndFindFileByPath(p["path"].asString) + if (file != null) OpenFileDescriptor(project, file, maxOf(0, (p["line"]?.asInt ?: 1) - 1), 0).navigate(true) + JsonParser.parseString((file != null).toString()) + } + "openExternal" -> { BrowserUtil.browse(p["url"].asString); JsonNull.INSTANCE } + "reveal" -> { RevealFileAction.openFile(File(p["path"].asString)); JsonNull.INSTANCE } + "copy" -> { CopyPasteManager.getInstance().setContents(StringSelection(p["text"].asString)); JsonNull.INSTANCE } + "notify" -> { + val type = when (p["level"]?.asString) { "error" -> NotificationType.ERROR; "warning" -> NotificationType.WARNING; else -> NotificationType.INFORMATION } + session.notify(p["message"].asString, type); JsonNull.INSTANCE + } + "openPanel" -> { + val rest = p.deepCopy().apply { remove("panel") } + McppPanels.show(project, p["panel"].asString, rest); JsonNull.INSTANCE + } + "runCommand" -> { Dispatch.run(project, p["command"].asString, p); JsonNull.INSTANCE } + "confirm" -> { + val detail = listOfNotNull(p["detail"]?.asString, p["preview"]?.asString?.takeIf { it.isNotBlank() }).joinToString("\n\n") + val yes = Messages.showOkCancelDialog(project, detail, p["title"].asString, session.t("Continue"), Messages.getCancelButton(), Messages.getWarningIcon()) == Messages.OK + var acknowledged = false + if (yes && p["acknowledge"]?.asBoolean == true) { + val ack = session.t("I understand this affects every mcpp project on this machine") + acknowledged = Messages.showOkCancelDialog(project, ack, p["title"].asString, ack, Messages.getCancelButton(), Messages.getWarningIcon()) == Messages.OK + } + JsonObject().apply { addProperty("confirmed", yes && (acknowledged || p["acknowledge"]?.asBoolean != true)); addProperty("acknowledged", acknowledged) } + } + "languageService" -> { Dispatch.languageServiceAction(project, p["action"]?.asString ?: "install"); JsonNull.INSTANCE } + else -> error("unknown host action $action") + } + } + + override fun dispose() { + unsubscribe() + query?.let { Disposer.dispose(it) } + browser?.let { Disposer.dispose(it) } + } +} diff --git a/jetbrains/src/main/resources/META-INF/mcpp-jcef.xml b/jetbrains/src/main/resources/META-INF/mcpp-jcef.xml new file mode 100644 index 0000000..c389eb5 --- /dev/null +++ b/jetbrains/src/main/resources/META-INF/mcpp-jcef.xml @@ -0,0 +1,2 @@ +<!-- Nothing to register: the dependency only makes its classes visible to this plugin. --> +<idea-plugin/> diff --git a/jetbrains/src/main/resources/META-INF/mcpp-testrunner.xml b/jetbrains/src/main/resources/META-INF/mcpp-testrunner.xml new file mode 100644 index 0000000..c389eb5 --- /dev/null +++ b/jetbrains/src/main/resources/META-INF/mcpp-testrunner.xml @@ -0,0 +1,2 @@ +<!-- Nothing to register: the dependency only makes its classes visible to this plugin. --> +<idea-plugin/> diff --git a/jetbrains/src/main/resources/META-INF/plugin.xml b/jetbrains/src/main/resources/META-INF/plugin.xml new file mode 100644 index 0000000..a5ae59b --- /dev/null +++ b/jetbrains/src/main/resources/META-INF/plugin.xml @@ -0,0 +1,49 @@ +<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude"> + <id>io.github.mcpp-community.mcpp-clion</id> + <!-- The Marketplace refuses a product name in a plugin's name (TemplateWordInPluginName): the plugin + is "mcpp" there, its ID and its archive say mcpp-clion. --> + <name>mcpp</name> + <vendor url="https://github.com/mcpp-community/mcpp-ide">mcpp-community</vendor> + <resource-bundle>messages.McppClionBundle</resource-bundle> + + <description><![CDATA[ + Build, run, test, debug and pack <a href="https://github.com/mcpp-community/mcpp">mcpp</a> C++23 module + projects in CLion: an "mcpp" run configuration type with a PTY console and a ▶ beside <code>main</code>, + the test tree, CLion's own debugger, links in the console, and the mcpp tool window (project, libraries, + cache, targets and platforms, dependency and module graphs, pack, settings). + <br/><br/> + Language features of C++ files come from the C++ Modules language server (mcppls), whose CLion plugin + this one depends on; mcpp-clion registers no language service. The mcpp-ide backend it runs reads only + mcpp's machine contract, so CLion and VS Code (mcpp-vscode) behave alike. + ]]></description> + + <depends>com.intellij.modules.platform</depends> + <depends>com.intellij.modules.clion</depends> + <depends>com.intellij.modules.cidr.debugger</depends> + <depends>io.github.sunrisepeak.mcppls</depends> + <!-- Since 2026.1 the panels' browser and the test tree are plugins of their own; in 2025.2 they are + the platform's. Optional, so the classes are found either way. --> + <depends optional="true" config-file="mcpp-jcef.xml">com.intellij.modules.jcef</depends> + <depends optional="true" config-file="mcpp-testrunner.xml">intellij.testRunner.plugin</depends> + + <xi:include href="/META-INF/mcpp-actions.xml" xpointer="xpointer(/idea-plugin/*)"/> + + <extensions defaultExtensionNs="com.intellij"> + <applicationService serviceImplementation="io.github.mcppcommunity.mcppclion.settings.McppSettings"/> + <projectConfigurable parentId="tools" instance="io.github.mcppcommunity.mcppclion.settings.McppConfigurable" + id="io.github.mcppcommunity.mcppclion.settings" displayName="mcpp"/> + <postStartupActivity implementation="io.github.mcppcommunity.mcppclion.McppStartup"/> + <notificationGroup id="mcpp" displayType="BALLOON"/> + + <toolWindow id="mcpp" anchor="right" icon="io.github.mcppcommunity.mcppclion.McppIcons.Logo" + factoryClass="io.github.mcppcommunity.mcppclion.webui.McppPanels$Factory"/> + + <configurationType implementation="io.github.mcppcommunity.mcppclion.run.McppRunConfigurationType"/> + <runConfigurationProducer implementation="io.github.mcppcommunity.mcppclion.run.McppConfigurationProducer"/> + <programRunner implementation="io.github.mcppcommunity.mcppclion.run.McppDebugRunner"/> + <!-- C++ is CLion Nova's language id, ObjectiveC the classic engine's. --> + <runLineMarkerContributor language="C++" implementationClass="io.github.mcppcommunity.mcppclion.run.McppRunLineMarker"/> + <runLineMarkerContributor language="ObjectiveC" implementationClass="io.github.mcppcommunity.mcppclion.run.McppRunLineMarker"/> + <consoleFilterProvider implementation="io.github.mcppcommunity.mcppclion.run.McppConsoleFilterProvider"/> + </extensions> +</idea-plugin> diff --git a/jetbrains/src/main/resources/META-INF/pluginIcon.svg b/jetbrains/src/main/resources/META-INF/pluginIcon.svg new file mode 100644 index 0000000..132191f --- /dev/null +++ b/jetbrains/src/main/resources/META-INF/pluginIcon.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="40" height="40" viewBox="0 0 40 40"><rect x="2" y="2" width="36" height="36" rx="8" fill="#3574F0"/><text x="20" y="27" font-family="sans-serif" font-size="16" font-weight="700" text-anchor="middle" fill="#FFFFFF">m++</text></svg> diff --git a/jetbrains/src/main/resources/icons/mcpp.svg b/jetbrains/src/main/resources/icons/mcpp.svg new file mode 100644 index 0000000..5366045 --- /dev/null +++ b/jetbrains/src/main/resources/icons/mcpp.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="1" y="1" width="14" height="14" rx="3" fill="#3574F0"/><text x="8" y="11.5" font-family="sans-serif" font-size="8" font-weight="700" text-anchor="middle" fill="#FFFFFF">m+</text></svg> diff --git a/jetbrains/src/main/resources/icons/mcpp_dark.svg b/jetbrains/src/main/resources/icons/mcpp_dark.svg new file mode 100644 index 0000000..5366045 --- /dev/null +++ b/jetbrains/src/main/resources/icons/mcpp_dark.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16"><rect x="1" y="1" width="14" height="14" rx="3" fill="#3574F0"/><text x="8" y="11.5" font-family="sans-serif" font-size="8" font-weight="700" text-anchor="middle" fill="#FFFFFF">m+</text></svg> diff --git a/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt b/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt new file mode 100644 index 0000000..29fefff --- /dev/null +++ b/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt @@ -0,0 +1,77 @@ +// The wire and the backend, without an IDE: frames reassemble whatever the chunking; a session over +// the mock mcpp finds the project, runs a build to `ok`, and lists the commands this editor offers +// (no forward to mcppls's VS Code commands among them). The session test runs when the build passes +// the backend and the mock mcpp (MCPP_IDE_BACKEND, MCPP_IDE_MOCK_MCPP). +package io.github.mcppcommunity.mcppclion + +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonObject +import io.github.mcppcommunity.mcppclion.backend.Backend +import io.github.mcppcommunity.mcppclion.backend.FrameReader +import io.github.mcppcommunity.mcppclion.backend.Locate +import io.github.mcppcommunity.mcppclion.backend.encode +import org.junit.Assert.assertEquals +import org.junit.Assert.assertTrue +import org.junit.Assume.assumeTrue +import org.junit.Test +import java.io.File +import java.nio.file.Files +import java.util.concurrent.CompletableFuture +import java.util.concurrent.TimeUnit + +class BackendTest { + @Test + fun framesReassemble() { + val all = "Junk: 1\r\n\r\n".toByteArray() + encode(JsonObject().apply { addProperty("a", 1) }) + + encode(JsonObject().apply { addProperty("b", "é") }) + val reader = FrameReader() + val bodies = mutableListOf<String>() + for (b in all) bodies += reader.feed(byteArrayOf(b)) + assertEquals(listOf("""{"a":1}""", """{"b":"é"}"""), bodies) + } + + @Test + fun platformDirectories() { + assertEquals("linux-x64", Locate.platformDir("Linux", "amd64")) + assertEquals("darwin-arm64", Locate.platformDir("Mac OS X", "aarch64")) + assertEquals("win32-x64", Locate.platformDir("Windows 11", "x86_64")) + } + + @Test + fun sessionOverTheMockMcpp() { + val backend = System.getProperty("mcppide.backend") + val mock = System.getProperty("mcppide.mockMcpp") + assumeTrue("MCPP_IDE_BACKEND and MCPP_IDE_MOCK_MCPP name the programs", backend != null && mock != null) + val root = Files.createTempDirectory("mcppclion-").toFile() + File(root, "src").mkdirs() + File(root, "mcpp.toml").writeText("[package]\nname = \"app\"\nversion = \"0.1.0\"\n") + Backend(listOf(backend!!, "serve")).use { b -> + val init = b.request("initialize", JsonObject().apply { + addProperty("editor", "jetbrains") + add("settings", JsonObject().apply { addProperty("mcpp.path", mock) }) + add("workspaceFolders", JsonArray().apply { add(root.path) }) + }).get(30, TimeUnit.SECONDS).asJsonObject + assertEquals(1, init.getAsJsonArray("projects").size()) + val finished = CompletableFuture<JsonElement>() + b.on("job/finished") { _, p -> finished.complete(p) } + b.request("job/start", JsonObject().apply { addProperty("kind", "build"); addProperty("root", root.path) }).get(30, TimeUnit.SECONDS) + assertEquals("ok", finished.get(60, TimeUnit.SECONDS).asJsonObject["status"].asString) + val commands = b.request("commands/list", JsonObject().apply { addProperty("editor", "jetbrains") }).get(30, TimeUnit.SECONDS) + .asJsonObject.getAsJsonArray("commands").map { it.asJsonObject } + assertTrue(commands.any { it["id"].asString == "mcpp.build" }) + assertTrue(commands.none { it["action"].asJsonObject["kind"].asString == "forward" }) + } + root.deleteRecursively() + } + + @Test + fun theGeneratedActionsAreTheTables() { + val xml = javaClass.getResource("/META-INF/mcpp-actions.xml")?.readText() + assumeTrue("the generated resources are on the test classpath", xml != null) + assertTrue(xml!!.contains("""id="mcpp.build"""")) + assertTrue(!xml.contains("mcpp.languageServer.restart")) + val bundle = javaClass.getResource("/messages/McppClionBundle.properties")!!.readText() + assertTrue(bundle.contains("action.mcpp.build.text=Build")) + } +} From a48b73ebb44af981dc1fba4c26a630e4416eeb18 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 03:13:16 +0900 Subject: [PATCH 06/30] agents: driving the backend from an agent, and a skill Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- agents/README.md | 40 ++++++++++++++++++++++++++++ agents/skills/mcpp-ide/SKILL.md | 46 +++++++++++++++++++++++++++++++++ 2 files changed, 86 insertions(+) create mode 100644 agents/README.md create mode 100644 agents/skills/mcpp-ide/SKILL.md diff --git a/agents/README.md b/agents/README.md new file mode 100644 index 0000000..db130ee --- /dev/null +++ b/agents/README.md @@ -0,0 +1,40 @@ +# mcpp-ide for agents + +An agent drives an mcpp project the way the editors do: through the mcpp-ide backend, whose +protocol is JSON-RPC on the standard streams of `mcpp-ide serve` +([protocol/protocol.schema.json](../protocol/protocol.schema.json)). The backend answers the same +questions the panels ask -- which tests a project has, what a cleanup would remove, which platform +configures a target -- from mcpp's machine contract, so an agent and a person in the editor see the +same facts. + +An agent that only builds and tests needs none of this: `mcpp build --message-format json` and +`mcpp test --message-format json` are mcpp's own contract (mcpp docs/50, docs/52). The backend is +for what mcpp leaves to its clients: one job at a time per project, cleanup plans with their +danger levels, views of the cache, the libraries and the graphs, and the language service's state. + +## Getting the backend + +- `xlings install mcpp-ide`, or +- from a clone: `mcpp build`, then `target/<triple>/<fingerprint>/bin/mcpp-ide`. + +`mcpp-ide self-check` (or `self-check --json`) reports what the backend finds: the backend, mcpp +and its contract, mcppls, xlings, trust. + +## A session + +``` +→ initialize {"editor": "cli", "workspaceFolders": ["/path/to/project"]} +← result {"projects": [...], "mcpp": {...}, "languageService": {...}, "checks": [...]} +→ test/list {"root": "/path/to/project"} +→ job/start {"kind": "test", "root": "/path/to/project", "color": false} +← job/started, job/output, job/plan, test/result ..., test/summary, job/finished +→ shutdown, then the notification exit +``` + +Each message is framed as in LSP: `Content-Length: <n>\r\n\r\n<json>`. + +## The skill + +[skills/mcpp-ide/SKILL.md](skills/mcpp-ide/SKILL.md) is a skill for agents that load skills +(Claude Code and others): when to use the backend, the methods worth knowing, and how to read the +answers. diff --git a/agents/skills/mcpp-ide/SKILL.md b/agents/skills/mcpp-ide/SKILL.md new file mode 100644 index 0000000..ab8900b --- /dev/null +++ b/agents/skills/mcpp-ide/SKILL.md @@ -0,0 +1,46 @@ +--- +name: mcpp-ide +description: Drive an mcpp C++ project through the mcpp-ide backend (`mcpp-ide serve`, JSON-RPC on stdio) -- list tests without building, run builds and tests as serialized jobs with normalized results, inspect targets and the platform configuring each, plan cache cleanups with their danger level, and read package/module graphs. Use when a task needs more than `mcpp build`/`mcpp test` output, or the same facts an mcpp IDE panel shows. +--- + +# mcpp-ide + +The backend reads only mcpp's machine contract; it parses no mcpp.toml and resolves no +dependency. Its answers are the editors' answers. + +## Start + +1. `mcpp-ide self-check --json` -- is mcpp found, does it have the control contract (2026.10.26.1+), + which mcppls answers C++ files. +2. `mcpp-ide serve`, then `initialize` with `{"editor": "cli", "workspaceFolders": [<dir>]}`. + Frames: `Content-Length: <n>\r\n\r\n<json>`, both ways. + +## Methods worth knowing + +| Method | Answers | +|---|---| +| `test/list {root}` | every test, its workspace member and the file holding its `main`; no build | +| `job/start {kind: build\|test, root, target?, profile?, filter?}` | a job id; then `job/output`, `job/plan`, `job/diagnostic`, `test/result`, `test/summary`, `job/finished` | +| `job/cancel {jobId}` | mcpp ends the steps it started; the result record says `cancelled` | +| `targets/list {root}` | each target, its toolchains, `installed`, and `platform` (name, version, source, fields) | +| `project/summary {root}` | executables, tests, libraries, last build, the platforms the last plan named | +| `run/launch {root, target?}` | builds; argv, env and cwd that start the program | +| `cache/plan {action}` | argv, danger `level` (0-3), `preview`, whether acknowledgement is required | +| `graph/packages {root}`, `graph/modules {root}` | nodes and edges | +| `manifest/check {root}` | mcpp.toml's problems, located | + +## Reading results + +- `job/finished.status`: `ok`, `failed`, `cancelled`, `denied` (an effect was denied: exit code 5), + `superseded` (a newer job of the same kind replaced it). +- `test/result.status`: `passed`, `failed`, `timedOut`, `skipped`, `errored`; `output` is the + test's compile and run output. +- Diagnostics are 1-based `{line, column}`, with `path` absolute. +- A cleanup at level > 0 is applied only with `cache/apply {action, confirmation: {confirmed, + previewShown, acknowledged}}` -- ask the person before you set those. + +## Do not + +- Do not edit mcpp.toml to add a dependency: `library/add` runs `mcpp add`. +- Do not run cleanups of level 2 or 3 without the person's explicit consent: they remove entries + other projects on the machine use. From d881c4951296533a38b7d1a99820ea356538c9bd Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 03:13:16 +0900 Subject: [PATCH 07/30] CI, release, README (en, zh-CN) and the architecture CI: the backend built and tested on Linux, macOS and Windows; the extension's unit and panel tests, its extension-host suite in VS Code 1.91 and its package; the plugin's tests, archive and Plugin Verifier run. Release: a backend per system laid out bin/<platform>/, both editor packages carrying all of them, and a GitHub release with checksums; the Marketplaces are uploaded to by the maintainer from those assets. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/actions/setup-mcpp/action.yml | 60 ++++++++++++ .github/versions.env | 9 ++ .github/workflows/ci.yml | 133 ++++++++++++++++++++++++++ .github/workflows/release.yml | 106 ++++++++++++++++++++ CHANGELOG.md | 16 ++++ README.md | 90 +++++++++++++++++ README.zh-CN.md | 83 ++++++++++++++++ docs/README.md | 7 ++ docs/architecture.md | 46 +++++++++ 9 files changed, 550 insertions(+) create mode 100644 .github/actions/setup-mcpp/action.yml create mode 100644 .github/versions.env create mode 100644 .github/workflows/ci.yml create mode 100644 .github/workflows/release.yml create mode 100644 CHANGELOG.md create mode 100644 README.md create mode 100644 README.zh-CN.md create mode 100644 docs/README.md create mode 100644 docs/architecture.md diff --git a/.github/actions/setup-mcpp/action.yml b/.github/actions/setup-mcpp/action.yml new file mode 100644 index 0000000..dc83a77 --- /dev/null +++ b/.github/actions/setup-mcpp/action.yml @@ -0,0 +1,60 @@ +name: Set up mcpp +description: Install xlings, the pinned mcpp and (for macOS and Windows targets) the pinned LLVM, with the package store cached. +inputs: + llvm: + description: Install LLVM and make it mcpp's default toolchain. + default: 'false' +runs: + using: composite + steps: + - name: Version pins + shell: bash + run: | + set -euo pipefail + while IFS='=' read -r name value; do + case "$name" in ''|\#*) continue ;; esac + if [ -z "${!name:-}" ]; then echo "$name=$value" >> "$GITHUB_ENV"; fi + done < .github/versions.env + - name: Install xlings (Unix) + if: runner.os != 'Windows' + shell: bash + run: | + curl -fsSL --retry 3 --retry-all-errors --retry-delay 2 \ + https://raw.githubusercontent.com/openxlings/xlings/main/tools/other/quick_install.sh \ + | bash -s "$XLINGS_VERSION" + echo "$HOME/.xlings/subos/current/bin" >> "$GITHUB_PATH" + - name: Install xlings (Windows) + if: runner.os == 'Windows' + shell: pwsh + run: | + irm https://d2learn.org/xlings-install.ps1.txt | iex + "$env:USERPROFILE\.xlings\subos\current\bin" | Out-File -FilePath $env:GITHUB_PATH -Encoding utf8 -Append + - name: Cache the mcpp package store + uses: actions/cache@v5 + with: + path: ~/.mcpp/registry/data/xpkgs + key: mcpp-xpkgs-${{ runner.os }}-${{ env.MCPP_VERSION }}-${{ hashFiles('mcpp.toml', 'mcpp.lock') }} + restore-keys: mcpp-xpkgs-${{ runner.os }}-${{ env.MCPP_VERSION }}- + - name: Install mcpp + shell: bash + run: | + set -euo pipefail + for attempt in 1 2 3 4 5; do + xlings update > /dev/null 2>&1 || true + if xlings install "mcpp@$MCPP_VERSION" -y -g; then break; fi + [ "$attempt" = 5 ] && { echo "::error::mcpp@$MCPP_VERSION could not be installed"; exit 1; } + sleep 30 + done + mcpp --version + mcpp self config --mirror GLOBAL + - name: Install LLVM + if: inputs.llvm == 'true' + shell: bash + run: | + set -euo pipefail + for attempt in 1 2 3; do + if mcpp toolchain install llvm "$LLVM_VERSION"; then break; fi + [ "$attempt" = 3 ] && exit 1 + sleep 30 + done + mcpp toolchain default "llvm@$LLVM_VERSION" diff --git a/.github/versions.env b/.github/versions.env new file mode 100644 index 0000000..da8fcbd --- /dev/null +++ b/.github/versions.env @@ -0,0 +1,9 @@ +# The versions CI builds and tests with, in one file; .github/actions/setup-mcpp exports them. +# The mcpp whose control contract the fixtures were captured from (protocol/fixtures/version.txt). +MCPP_VERSION=2026.10.26.2 +# The LLVM the backend builds with on macOS and Windows (the targets mcpp reaches there with it). +LLVM_VERSION=23.1.3 +# The xlings mcpp 2026.10.26.2 bundles, which reads the current index. +XLINGS_VERSION=v2026.10.26.1 +# The oldest VS Code the extension supports (engines.vscode), which its tests run in. +VSCODE_VERSION=1.91.0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..dc8de5a --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,133 @@ +name: CI + +on: + push: + branches: [main] + pull_request: + workflow_dispatch: + workflow_call: + +concurrency: + group: ci-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + XLINGS_NON_INTERACTIVE: '1' + +jobs: + # The backend on each system: build (every program: the backend, the mock mcpp, the dev tool), + # then the tests -- the protocol against its schema and the fixtures against mcpp's contract + # among them -- and the translations. + backend: + name: backend (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + strategy: + fail-fast: false + matrix: + include: + - { os: ubuntu-24.04, target: '', llvm: 'false', platform: linux-x64 } + - { os: macos-14, target: '--target aarch64-macos', llvm: 'true', platform: darwin-arm64 } + - { os: windows-2022, target: '--target x86_64-windows-gnu', llvm: 'true', platform: win32-x64 } + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v5 + - uses: ./.github/actions/setup-mcpp + with: + llvm: ${{ matrix.llvm }} + - name: Build + run: mcpp build ${{ matrix.target }} + - name: Test + run: mcpp test ${{ matrix.target }} + - name: Every string has its translation + run: mcpp run ${{ matrix.target }} mcpp-ide-dev -- check-i18n + - name: The backend answers + run: mcpp run ${{ matrix.target }} mcpp-ide -- --version + + # The VS Code extension: unit tests (the wire, the mappings) and the shared panels in a DOM, both + # against the backend built here; then the extension in a real VS Code (the oldest it supports) + # over the mock mcpp; then the package, and its file list. + vscode: + name: VS Code extension + runs-on: ubuntu-24.04 + timeout-minutes: 45 + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v5 + - uses: ./.github/actions/setup-mcpp + - uses: actions/setup-node@v5 + with: + node-version: 22 + cache: npm + cache-dependency-path: vscode/package-lock.json + - name: Build the backend + run: mcpp build + - name: Install + working-directory: vscode + run: npm ci + - name: Unit and panel tests + working-directory: vscode + run: npm test + - name: The panels type-check + working-directory: vscode + run: npm run check:webui + - name: The extension in VS Code ${{ env.VSCODE_VERSION }} + working-directory: vscode + run: | + mkdir -p dist/backends/linux-x64 + cp "$(ls -t ../target/*/*/bin/mcpp-ide | head -1)" dist/backends/linux-x64/ + export MCPP_IDE_BACKENDS="$PWD/dist/backends" + xvfb-run -a npm run test:e2e + - name: Package + working-directory: vscode + run: | + export MCPP_IDE_BACKENDS="$PWD/dist/backends" + npm run package + cd dist/extension && npx vsce ls --no-dependencies + - uses: actions/upload-artifact@v5 + with: + name: mcpp-vscode-ci + path: vscode/dist/*.vsix + + # The CLion plugin: its tests (the wire and a session over the mock mcpp), the archive, and the + # Plugin Verifier against the oldest CLion it claims (2025.2) and the one it is built on. + jetbrains: + name: CLion plugin + runs-on: ubuntu-24.04 + timeout-minutes: 90 + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v5 + - uses: ./.github/actions/setup-mcpp + - name: Gradle (xim:gradle brings its JDK) + run: xlings install gradle -y -g + - uses: actions/cache@v5 + with: + path: | + ~/.gradle/caches/modules-2 + ~/.gradle/caches/transforms-4 + jetbrains/.intellijPlatform + key: gradle-clion-${{ hashFiles('jetbrains/gradle.properties', 'jetbrains/build.gradle.kts') }} + - name: Build the backend + run: mcpp build + - name: Test and build + working-directory: jetbrains + run: | + bin="$(dirname "$(ls -t ../target/*/*/bin/mcpp-ide | head -1)")" + export MCPP_IDE_DEV="$bin/mcpp-ide-dev" MCPP_IDE_BACKEND="$bin/mcpp-ide" MCPP_IDE_MOCK_MCPP="$bin/mcpp-ide-mock-mcpp" + gradle --no-daemon test buildPlugin + - name: Plugin Verifier + working-directory: jetbrains + run: | + export MCPP_IDE_DEV="$(ls -t ../target/*/*/bin/mcpp-ide-dev | head -1)" + gradle --no-daemon verifyPlugin + - uses: actions/upload-artifact@v5 + with: + name: mcpp-clion-ci + path: jetbrains/build/distributions/*.zip diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 0000000..0933e20 --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,106 @@ +name: Release + +# A release: CI on the tagged commit, the backend for each system the editors run on, the VS Code +# extension and the CLion plugin carrying all of them, and a GitHub release with both packages and +# their checksums. The two Marketplaces are uploaded to by the maintainer, from those assets. +# +# The backends are built per system here. When mcpp's platforms ship (mcpp design 2026-10-28), each +# becomes one ok image per architecture (`mcpp build --target <arch>-openkal`) made into a program +# of each system by `mcpp pack --mode self-contained`; only the `backend` job changes, the layout +# it uploads (`bin/<platform>/mcpp-ide[.exe]`) does not. + +on: + workflow_dispatch: + push: + tags: ['v*'] + +permissions: + contents: write + +env: + XLINGS_NON_INTERACTIVE: '1' + +jobs: + ci: + uses: ./.github/workflows/ci.yml + + backend: + name: backend (${{ matrix.platform }}) + needs: ci + runs-on: ${{ matrix.os }} + timeout-minutes: 60 + strategy: + fail-fast: true + matrix: + include: + - { os: ubuntu-24.04, platform: linux-x64, target: '--target x86_64-linux-musl', llvm: 'false', exe: mcpp-ide } + - { os: ubuntu-24.04-arm, platform: linux-arm64, target: '--target aarch64-linux-musl', llvm: 'false', exe: mcpp-ide } + - { os: macos-14, platform: darwin-arm64, target: '--target aarch64-macos', llvm: 'true', exe: mcpp-ide } + - { os: windows-2022, platform: win32-x64, target: '--target x86_64-windows-gnu', llvm: 'true', exe: mcpp-ide.exe } + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v5 + - uses: ./.github/actions/setup-mcpp + with: + llvm: ${{ matrix.llvm }} + - name: Build + run: mcpp build --release ${{ matrix.target }} + - name: Lay out bin/${{ matrix.platform }} + run: | + mkdir -p "out/${{ matrix.platform }}" + cp "$(ls -t target/*/*/bin/${{ matrix.exe }} | head -1)" "out/${{ matrix.platform }}/" + "out/${{ matrix.platform }}/${{ matrix.exe }}" --version + - uses: actions/upload-artifact@v5 + with: + name: backend-${{ matrix.platform }} + path: out + + package: + name: packages + needs: backend + runs-on: ubuntu-24.04 + timeout-minutes: 60 + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v5 + - uses: ./.github/actions/setup-mcpp + - uses: actions/setup-node@v5 + with: + node-version: 22 + - uses: actions/download-artifact@v5 + with: + pattern: backend-* + path: backends + merge-multiple: true + - name: Backends are executable + run: chmod +x backends/*/mcpp-ide* && ls -lR backends + - name: Build the dev tool + run: mcpp build + - name: VS Code extension + working-directory: vscode + run: | + npm ci + MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" npm run package + (cd dist/extension && npx vsce ls --no-dependencies) + - name: Gradle (xim:gradle brings its JDK) + run: xlings install gradle -y -g + - name: CLion plugin + working-directory: jetbrains + run: | + export MCPP_IDE_DEV="$(ls -t ../target/*/*/bin/mcpp-ide-dev | head -1)" MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" + gradle --no-daemon buildPlugin + - name: Release + env: + GH_TOKEN: ${{ github.token }} + run: | + version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" + mkdir -p dist + cp "vscode/dist/mcpp-vscode-$(node -p "require('./vscode/package.json').version").vsix" dist/ + cp jetbrains/build/distributions/mcpp-clion-*.zip dist/ + (cd backends && for d in */; do tar -czf "../dist/mcpp-ide-${version}-${d%/}.tar.gz" -C "$d" .; done) + (cd dist && sha256sum * > SHA256SUMS) + gh release create "v${version}" dist/* --target "$GITHUB_SHA" --title "mcpp-ide ${version}" --notes-file CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..e451079 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,16 @@ +# Changelog + +## 0.1.0 + +The first release of mcpp-ide: one backend for mcpp's editor integrations, the VS Code extension +(mcpp-vscode 1.0.0, the same extension ID as before) and the CLion plugin (mcpp-clion 0.1.0). + +- Backend (`mcpp-ide serve`): sessions, watching, jobs, view models, cleanup plans, settings, the + command table, runtime strings, self-check; handshakes with mcpp and mcppls; targets with their + platforms. +- Protocol and contract schemas, held against mcpp 2026.10.26.2's real output. +- Shared panels: project, targets and platforms, libraries, dependency and module graphs, cache, + pack, settings. +- VS Code: tasks, Testing view, debug configurations, Problems from mcpp, mcpp.toml editing help. +- CLion: run configurations with a PTY console, test tree, CLion's debugger, console links, the mcpp + tool window; depends on the mcppls CLion plugin. diff --git a/README.md b/README.md new file mode 100644 index 0000000..86486b9 --- /dev/null +++ b/README.md @@ -0,0 +1,90 @@ +# mcpp-ide - the IDE layer of mcpp + +> One backend for every editor of [mcpp](https://github.com/mcpp-community/mcpp) projects: VS Code +> (mcpp-vscode) and CLion (mcpp-clion) build, run, test, debug and pack alike + +**English** | [简体中文](README.zh-CN.md) + +[Documentation](docs/README.md) · [Protocol](protocol/protocol.schema.json) · [Settings](spec/settings.json) · +[For agents](agents/README.md) · [Releases](https://github.com/mcpp-community/mcpp-ide/releases) + +An editor integration of a build tool decides a great deal: which command a build runs, what a +test result means, how dangerous a cleanup is, which target a project builds for. Written once per +editor, those decisions drift apart, and a person who moves from one editor to another meets a +different tool. + +mcpp-ide makes them once. Its backend, `mcpp-ide serve`, is a C++ program that reads only mcpp's +machine contract (event streams, result records, launch descriptors, JSON queries) and answers the +editors over JSON-RPC. The VS Code extension and the CLion plugin map those answers onto their own +UI and share one set of web panels. Language features of C++ files come from +[mcppls](https://github.com/Sunrisepeak/mcpp-language-server); mcpp-ide registers none. + +## Features + +| | VS Code (mcpp-vscode) | CLion (mcpp-clion) | +|---|---|---| +| Build, run, test | Tasks in a pseudoterminal showing mcpp's output | "mcpp" run configurations, PTY console, ▶ beside `main` | +| Test tree, re-run one test | Testing view | IDE test runner | +| Debug | CodeLLDB, C/C++ (gdb, lldb), lldb-dap | CLion's GDB or LLDB | +| Diagnostics | Problems, from mcpp's located diagnostics | Console links to the reported location | +| mcpp.toml | Problems from mcpp; completion, hover, outline from mcpp's key registry | Problems from mcpp | +| Targets and platforms, libraries, graphs, cache, pack, settings | Shared web panels | The same panels (JCEF) | +| Language features | mcppls (installed with the extension) | mcppls CLion plugin (a dependency) | + +- **One answer everywhere** -- what a build runs, how a test is reported, what a cleanup costs: the backend's +- **Only mcpp's contract** -- no manifest parsing, no dependency resolution of its own +- **Jobs in order** -- one at a time per project, a newer build replaces a waiting one, cancelling ends cleanly +- **Platforms visible** -- each target with the platform that configures it and where every value came from +- **Safe cleanups** -- a plan with a danger level, a preview and the confirmation that level requires + +## Install + +### From an agent + +``` +Read agents/README.md of https://github.com/mcpp-community/mcpp-ide, then install mcpp-ide for +the editor I use (VS Code or CLion) from its latest release, and check it with `mcpp-ide self-check` +on my mcpp project. +``` + +### From a release + +| Editor | Asset | Install | +|---|---|---| +| VS Code | the Marketplace (`mcpp-community.mcpp-vscode`), or `mcpp-vscode-<version>.vsix` | search *mcpp*, or `code --install-extension mcpp-vscode-<version>.vsix` | +| VS Code-compatible editors | Open VSX, or the `.vsix` | install the `.vsix` from the extensions view | +| CLion 2025.2+ | JetBrains Marketplace (`mcpp-clion`), or `mcpp-clion-<version>.zip` | Settings → Plugins → Install Plugin from Disk; the mcppls CLion plugin first | +| Agents, other clients | `mcpp-ide-<version>-<platform>.tar.gz`, or `xlings install mcpp-ide` | run `mcpp-ide serve` | + +Both editor packages carry the backend for Linux, macOS and Windows. + +### From source + +```bash +mcpp build # the backend, the mock mcpp, mcpp-ide-dev +mcpp test # the backend's tests +cd vscode && npm ci && npm test # the extension's and the panels' tests +npm run package # dist/mcpp-vscode-<version>.vsix +cd ../jetbrains && gradle buildPlugin verifyPlugin # build/distributions/mcpp-clion-<version>.zip +``` + +`xlings install gradle` brings Gradle and its JDK. + +## Documentation + +- [docs/architecture.md](docs/architecture.md) -- the three layers and their boundaries +- [protocol/protocol.schema.json](protocol/protocol.schema.json) -- the backend's methods and notifications +- [protocol/mcpp-contract.schema.json](protocol/mcpp-contract.schema.json) -- the part of mcpp's contract it reads +- [spec/](spec) -- settings, commands, translations: the source of both editors' declarations +- [vscode/README.md](vscode/README.md), [jetbrains/README.md](jetbrains/README.md) + +## Contributing + +The backend is C++23 with modules, built by mcpp; the repository's tools are a program of it +(`mcpp-ide-dev`: fixture capture, the editors' declarations, the translation check). Generated +files are not committed. A change to what mcpp reports starts with `mcpp-ide-dev capture` and the +diff in `protocol/fixtures`. + +## License + +Apache-2.0 diff --git a/README.zh-CN.md b/README.zh-CN.md new file mode 100644 index 0000000..9416975 --- /dev/null +++ b/README.zh-CN.md @@ -0,0 +1,83 @@ +# mcpp-ide - mcpp 的 IDE 层 + +> 所有编辑器共用一个后端来对待 [mcpp](https://github.com/mcpp-community/mcpp) 工程:VS Code(mcpp-vscode) +> 与 CLion(mcpp-clion)的构建、运行、测试、调试、打包行为一致 + +[English](README.md) | **简体中文** + +[文档](docs/README.md) · [协议](protocol/protocol.schema.json) · [设置](spec/settings.json) · +[面向 Agent](agents/README.md) · [发布](https://github.com/mcpp-community/mcpp-ide/releases) + +构建工具的编辑器集成要做许多决定:构建运行哪条命令、测试结果是什么含义、一次清理有多危险、工程为哪个目标构建。 +每个编辑器各写一遍,这些决定就会分歧;从一个编辑器换到另一个,用户遇到的就是另一个工具。 + +mcpp-ide 只做一次。它的后端 `mcpp-ide serve` 是一个 C++ 程序,只读取 mcpp 的机器契约(事件流、结果记录、启动描述、 +JSON 查询),通过 JSON-RPC 回答编辑器。VS Code 扩展与 CLion 插件把这些回答映射到各自的界面,并共用一套网页面板。 +C++ 文件的语言功能来自 [mcppls](https://github.com/Sunrisepeak/mcpp-language-server);mcpp-ide 不注册任何语言服务。 + +## 功能 + +| | VS Code(mcpp-vscode) | CLion(mcpp-clion) | +|---|---|---| +| 构建、运行、测试 | 伪终端中的任务,显示 mcpp 自身的输出 | "mcpp" 运行配置、PTY 控制台、`main` 旁的 ▶ | +| 测试树、单个测试重跑 | 测试视图 | IDE 测试运行器 | +| 调试 | CodeLLDB、C/C++(gdb、lldb)、lldb-dap | CLion 的 GDB 或 LLDB | +| 诊断 | 问题面板,来自 mcpp 带位置的诊断 | 控制台链接到报告的位置 | +| mcpp.toml | 问题来自 mcpp;补全、悬停、大纲来自 mcpp 的键注册表 | 问题来自 mcpp | +| 目标与平台、库、依赖图、缓存、打包、设置 | 共享网页面板 | 同一套面板(JCEF) | +| 语言功能 | mcppls(随扩展一并安装) | mcppls CLion 插件(依赖) | + +- **处处同一答案**——构建运行什么、测试如何报告、清理的代价:都由后端决定 +- **只读 mcpp 的契约**——不自行解析清单,不自行解析依赖 +- **任务有序**——每个工程同一时间一个任务,新构建替换等待中的构建,取消会正常结束 +- **平台可见**——每个目标连同配置它的平台,以及每个值的来源 +- **安全清理**——带危险等级与预览的计划,按该等级要求确认 + +## 安装 + +### 让 Agent 安装 + +``` +阅读 https://github.com/mcpp-community/mcpp-ide 的 agents/README.md,为我使用的编辑器(VS Code 或 CLion) +从最新发布安装 mcpp-ide,并在我的 mcpp 工程上用 `mcpp-ide self-check` 检查。 +``` + +### 从 release 安装 + +| 编辑器 | 资产 | 安装 | +|---|---|---| +| VS Code | Marketplace(`mcpp-community.mcpp-vscode`),或 `mcpp-vscode-<version>.vsix` | 搜索 *mcpp*,或 `code --install-extension mcpp-vscode-<version>.vsix` | +| 兼容 VS Code 的编辑器 | Open VSX,或 `.vsix` | 在扩展视图中安装 `.vsix` | +| CLion 2025.2+ | JetBrains Marketplace(`mcpp-clion`),或 `mcpp-clion-<version>.zip` | Settings → Plugins → Install Plugin from Disk;先安装 mcppls CLion 插件 | +| Agent、其他客户端 | `mcpp-ide-<version>-<platform>.tar.gz`,或 `xlings install mcpp-ide` | 运行 `mcpp-ide serve` | + +两个编辑器的包都带有 Linux、macOS、Windows 的后端。 + +### 从源码构建 + +```bash +mcpp build # 后端、mock mcpp、mcpp-ide-dev +mcpp test # 后端测试 +cd vscode && npm ci && npm test # 扩展与面板的测试 +npm run package # dist/mcpp-vscode-<version>.vsix +cd ../jetbrains && gradle buildPlugin verifyPlugin # build/distributions/mcpp-clion-<version>.zip +``` + +`xlings install gradle` 会一并带来 Gradle 及其 JDK。 + +## 文档 + +- [docs/architecture.md](docs/architecture.md)——三层及其边界 +- [protocol/protocol.schema.json](protocol/protocol.schema.json)——后端的方法与通知 +- [protocol/mcpp-contract.schema.json](protocol/mcpp-contract.schema.json)——后端读取的 mcpp 契约部分 +- [spec/](spec)——设置、命令、翻译:两个编辑器声明的唯一来源 +- [vscode/README.md](vscode/README.md)、[jetbrains/README.md](jetbrains/README.md) + +## 参与贡献 + +后端是用 mcpp 构建的 C++23 模块程序;仓库的工具是它的一个程序(`mcpp-ide-dev`:抓取 fixture、生成编辑器声明、 +检查翻译)。生成物不提交。mcpp 的输出有变化时,从 `mcpp-ide-dev capture` 与 `protocol/fixtures` 的差异开始。 + +## 许可证 + +Apache-2.0 diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 0000000..8e40105 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,7 @@ +# mcpp-ide documentation + +- [architecture.md](architecture.md) -- the three layers, what each holds, and how a request travels +- [../protocol/protocol.schema.json](../protocol/protocol.schema.json) -- the backend's protocol +- [../agents/README.md](../agents/README.md) -- driving the backend from an agent +- [../vscode/README.md](../vscode/README.md) -- the VS Code extension +- [../jetbrains/README.md](../jetbrains/README.md) -- the CLion plugin diff --git a/docs/architecture.md b/docs/architecture.md new file mode 100644 index 0000000..5fb9bd6 --- /dev/null +++ b/docs/architecture.md @@ -0,0 +1,46 @@ +# Architecture + +## Three layers + +| Layer | Holds | Does not hold | +|---|---|---| +| mcpp | the machine contract: event streams, result records, launch descriptors, JSON queries, `--deny` (mcpp docs/50) | any IDE concept | +| mcpp-ide backend (`src/`) | sessions and projects (which mcpp.toml a file belongs to), watching (result records, manifests), jobs (one at a time per project, cancellation, a newer job replacing a waiting one), view models (project, targets and platforms, cache, libraries, graphs), cleanup plans and their danger levels, settings validation and migration, the command table, runtime strings, the self-check, the handshakes with mcpp (`--protocol-version`) and mcppls (`--version`) | parsing mcpp.toml, resolving dependencies | +| adapters (`vscode/`, `jetbrains/`) | declarations generated from `spec/`, the protocol mapped onto native UI, the panels' host, the backend process, finding the backend, workspace trust | any decision | + +The panels (`webui/`) are one set of classic scripts that both editors load: a VS Code webview and a +JCEF page. A panel speaks the backend's protocol through its host and asks the host only for what +the editor does (open a file, confirm, store a setting). + +## Language features + +mcppls provides every language feature of C++ files; mcpp-ide registers no language service. The +VS Code extension installs mcppls as an extension pack (it can be removed); the CLion plugin depends +on the mcppls CLion plugin. The backend reads `mcppls --version`: 0.0.18 and later refresh after any +build through mcpp's result record, and an older or missing mcppls is reported with what to do. + +## A build, end to end + +1. The user runs Build. The adapter sends `job/start {kind: "build", root}`. +2. The backend queues it on the project's lane and runs `mcpp build --message-format json` with + `MCPP_CLIENT`, colour for a terminal, and `MCPP_DENY_EFFECTS` in an untrusted workspace. +3. mcpp's narration becomes `job/output`; each event becomes `job/plan`, `job/progress`, + `job/diagnostic` or `job/artifact`; the closing envelope arrives in `job/finished`. +4. VS Code shows the narration in a pseudoterminal and the diagnostics in Problems; CLion shows the + narration in a console and its locations as links. +5. mcpp writes the result record; the backend's watcher sends `result/changed`; mcppls reads the + same record and refreshes. + +## Generated declarations + +`spec/` is the source of everything the editors declare statically. `mcpp-ide-dev gen vscode` writes +the extension's package.json (commands, keybindings, menus, configuration) and its message bundles; +`mcpp-ide-dev gen jetbrains` writes the plugin's actions and message bundles. The backend embeds the +same files (build.mcpp), so the commands an editor registers at run time are the ones it declared. + +## Fixtures + +`protocol/fixtures` holds mcpp's real output, captured by `mcpp-ide-dev capture`. The backend's tests +check each fixture against `protocol/mcpp-contract.schema.json`, replay them through the mock mcpp, +and check the backend's answers against `protocol/protocol.schema.json`; the adapters' tests run on +the same mock. From f43a610d4fd4a3d89832a7939f56a2f871e82993 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 03:24:44 +0900 Subject: [PATCH 08/30] CI builds every system's release backend and packages both editors with all four; the mock mcpp ends with _Exit (MinGW has no quick_exit) The release workflow publishes the packages CI built and checked. A bundled backend whose mode bits an archive dropped is made executable before it is started. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/workflows/ci.yml | 98 ++++++++++++++++++++++------------- .github/workflows/release.yml | 87 +++++-------------------------- src/bin/mockmcpp.cpp | 2 +- vscode/src/backend/locate.ts | 8 ++- 4 files changed, 83 insertions(+), 112 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc8de5a..69d328f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -15,20 +15,26 @@ env: XLINGS_NON_INTERACTIVE: '1' jobs: - # The backend on each system: build (every program: the backend, the mock mcpp, the dev tool), - # then the tests -- the protocol against its schema and the fixtures against mcpp's contract - # among them -- and the translations. + # The backend on each system the editors run on: build every program (the backend, the mock mcpp, + # the dev tool), run the tests -- the protocol against its schema and the fixtures against mcpp's + # contract among them -- check the translations, then build the release program the editor + # packages carry, laid out bin/<platform>/. + # + # When mcpp's platforms ship (mcpp design 2026-10-28), the release program becomes one ok image per + # architecture (`--target <arch>-openkal`) made into a program of each system by + # `mcpp pack --mode self-contained`; only the last two steps change, not the layout they upload. backend: - name: backend (${{ matrix.os }}) + name: backend (${{ matrix.platform }}) runs-on: ${{ matrix.os }} timeout-minutes: 60 strategy: fail-fast: false matrix: include: - - { os: ubuntu-24.04, target: '', llvm: 'false', platform: linux-x64 } - - { os: macos-14, target: '--target aarch64-macos', llvm: 'true', platform: darwin-arm64 } - - { os: windows-2022, target: '--target x86_64-windows-gnu', llvm: 'true', platform: win32-x64 } + - { os: ubuntu-24.04, platform: linux-x64, target: '', release: '--target x86_64-linux-musl', llvm: 'false', exe: mcpp-ide } + - { os: ubuntu-24.04-arm, platform: linux-arm64, target: '', release: '--target aarch64-linux-musl', llvm: 'false', exe: mcpp-ide } + - { os: macos-14, platform: darwin-arm64, target: '--target aarch64-macos', release: '--target aarch64-macos', llvm: 'true', exe: mcpp-ide } + - { os: windows-2022, platform: win32-x64, target: '--target x86_64-windows-gnu', release: '--target x86_64-windows-gnu', llvm: 'true', exe: mcpp-ide.exe } defaults: run: shell: bash @@ -43,14 +49,23 @@ jobs: run: mcpp test ${{ matrix.target }} - name: Every string has its translation run: mcpp run ${{ matrix.target }} mcpp-ide-dev -- check-i18n - - name: The backend answers - run: mcpp run ${{ matrix.target }} mcpp-ide -- --version + - name: Release program + run: | + mcpp build --release ${{ matrix.release }} + mkdir -p "out/${{ matrix.platform }}" + cp "$(ls -t target/*/*/bin/${{ matrix.exe }} | head -1)" "out/${{ matrix.platform }}/" + "out/${{ matrix.platform }}/${{ matrix.exe }}" --version + - uses: actions/upload-artifact@v5 + with: + name: backend-${{ matrix.platform }} + path: out # The VS Code extension: unit tests (the wire, the mappings) and the shared panels in a DOM, both - # against the backend built here; then the extension in a real VS Code (the oldest it supports) - # over the mock mcpp; then the package, and its file list. + # against the backend built here; the extension in a real VS Code (the oldest it supports) over the + # mock mcpp; then the package carrying every system's backend, and its file list. vscode: name: VS Code extension + needs: backend runs-on: ubuntu-24.04 timeout-minutes: 45 defaults: @@ -64,8 +79,15 @@ jobs: node-version: 22 cache: npm cache-dependency-path: vscode/package-lock.json - - name: Build the backend - run: mcpp build + - uses: actions/download-artifact@v5 + with: + pattern: backend-* + path: backends + merge-multiple: true + - name: Build the backend and its test programs + run: | + chmod +x backends/*/mcpp-ide* + mcpp build - name: Install working-directory: vscode run: npm ci @@ -77,26 +99,25 @@ jobs: run: npm run check:webui - name: The extension in VS Code ${{ env.VSCODE_VERSION }} working-directory: vscode - run: | - mkdir -p dist/backends/linux-x64 - cp "$(ls -t ../target/*/*/bin/mcpp-ide | head -1)" dist/backends/linux-x64/ - export MCPP_IDE_BACKENDS="$PWD/dist/backends" - xvfb-run -a npm run test:e2e + run: MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" xvfb-run -a npm run test:e2e - name: Package working-directory: vscode run: | - export MCPP_IDE_BACKENDS="$PWD/dist/backends" - npm run package - cd dist/extension && npx vsce ls --no-dependencies + MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" npm run package + (cd dist/extension && npx vsce ls --no-dependencies) | tee files.txt + for p in linux-x64 linux-arm64 darwin-arm64; do grep -qx "bin/$p/mcpp-ide" files.txt; done + grep -qx "bin/win32-x64/mcpp-ide.exe" files.txt - uses: actions/upload-artifact@v5 with: - name: mcpp-vscode-ci + name: mcpp-vscode-vsix path: vscode/dist/*.vsix - # The CLion plugin: its tests (the wire and a session over the mock mcpp), the archive, and the - # Plugin Verifier against the oldest CLion it claims (2025.2) and the one it is built on. + # The CLion plugin: its tests (the wire and a session over the mock mcpp), the archive carrying + # every system's backend, and the Plugin Verifier against the oldest CLion it claims (2025.2) and + # the one it is built on. jetbrains: name: CLion plugin + needs: backend runs-on: ubuntu-24.04 timeout-minutes: 90 defaults: @@ -109,25 +130,32 @@ jobs: run: xlings install gradle -y -g - uses: actions/cache@v5 with: - path: | - ~/.gradle/caches/modules-2 - ~/.gradle/caches/transforms-4 - jetbrains/.intellijPlatform - key: gradle-clion-${{ hashFiles('jetbrains/gradle.properties', 'jetbrains/build.gradle.kts') }} - - name: Build the backend - run: mcpp build - - name: Test and build + path: ~/.gradle/caches/modules-2 + key: gradle-clion-${{ hashFiles('jetbrains/gradle.properties', 'jetbrains/build.gradle.kts', 'jetbrains/settings.gradle.kts') }} + - uses: actions/download-artifact@v5 + with: + pattern: backend-* + path: backends + merge-multiple: true + - name: Build the backend and its test programs + run: | + chmod +x backends/*/mcpp-ide* + mcpp build + - name: Test and package working-directory: jetbrains run: | - bin="$(dirname "$(ls -t ../target/*/*/bin/mcpp-ide | head -1)")" + bin="$(cd "$(dirname "$(ls -t ../target/*/*/bin/mcpp-ide | head -1)")" && pwd)" export MCPP_IDE_DEV="$bin/mcpp-ide-dev" MCPP_IDE_BACKEND="$bin/mcpp-ide" MCPP_IDE_MOCK_MCPP="$bin/mcpp-ide-mock-mcpp" + export MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" gradle --no-daemon test buildPlugin + unzip -l build/distributions/mcpp-clion-*.zip | tee files.txt + for p in linux-x64/mcpp-ide linux-arm64/mcpp-ide darwin-arm64/mcpp-ide win32-x64/mcpp-ide.exe; do grep -q "mcpp-clion/bin/$p" files.txt; done - name: Plugin Verifier working-directory: jetbrains run: | - export MCPP_IDE_DEV="$(ls -t ../target/*/*/bin/mcpp-ide-dev | head -1)" + export MCPP_IDE_DEV="$(cd "$(dirname "$(ls -t ../target/*/*/bin/mcpp-ide-dev | head -1)")" && pwd)/mcpp-ide-dev" gradle --no-daemon verifyPlugin - uses: actions/upload-artifact@v5 with: - name: mcpp-clion-ci + name: mcpp-clion-zip path: jetbrains/build/distributions/*.zip diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0933e20..4f0fdc4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,13 +1,8 @@ name: Release -# A release: CI on the tagged commit, the backend for each system the editors run on, the VS Code -# extension and the CLion plugin carrying all of them, and a GitHub release with both packages and -# their checksums. The two Marketplaces are uploaded to by the maintainer, from those assets. -# -# The backends are built per system here. When mcpp's platforms ship (mcpp design 2026-10-28), each -# becomes one ok image per architecture (`mcpp build --target <arch>-openkal`) made into a program -# of each system by `mcpp pack --mode self-contained`; only the `backend` job changes, the layout -# it uploads (`bin/<platform>/mcpp-ide[.exe]`) does not. +# A release: CI on the commit (which builds every system's backend and both editor packages carrying +# them), then a GitHub release with the packages, the backends and their checksums. The two +# Marketplaces are uploaded to by the maintainer, from those assets. on: workflow_dispatch: @@ -17,90 +12,32 @@ on: permissions: contents: write -env: - XLINGS_NON_INTERACTIVE: '1' - jobs: ci: uses: ./.github/workflows/ci.yml - backend: - name: backend (${{ matrix.platform }}) + release: needs: ci - runs-on: ${{ matrix.os }} - timeout-minutes: 60 - strategy: - fail-fast: true - matrix: - include: - - { os: ubuntu-24.04, platform: linux-x64, target: '--target x86_64-linux-musl', llvm: 'false', exe: mcpp-ide } - - { os: ubuntu-24.04-arm, platform: linux-arm64, target: '--target aarch64-linux-musl', llvm: 'false', exe: mcpp-ide } - - { os: macos-14, platform: darwin-arm64, target: '--target aarch64-macos', llvm: 'true', exe: mcpp-ide } - - { os: windows-2022, platform: win32-x64, target: '--target x86_64-windows-gnu', llvm: 'true', exe: mcpp-ide.exe } - defaults: - run: - shell: bash - steps: - - uses: actions/checkout@v5 - - uses: ./.github/actions/setup-mcpp - with: - llvm: ${{ matrix.llvm }} - - name: Build - run: mcpp build --release ${{ matrix.target }} - - name: Lay out bin/${{ matrix.platform }} - run: | - mkdir -p "out/${{ matrix.platform }}" - cp "$(ls -t target/*/*/bin/${{ matrix.exe }} | head -1)" "out/${{ matrix.platform }}/" - "out/${{ matrix.platform }}/${{ matrix.exe }}" --version - - uses: actions/upload-artifact@v5 - with: - name: backend-${{ matrix.platform }} - path: out - - package: - name: packages - needs: backend runs-on: ubuntu-24.04 - timeout-minutes: 60 defaults: run: shell: bash steps: - uses: actions/checkout@v5 - - uses: ./.github/actions/setup-mcpp - - uses: actions/setup-node@v5 - with: - node-version: 22 - uses: actions/download-artifact@v5 with: - pattern: backend-* - path: backends - merge-multiple: true - - name: Backends are executable - run: chmod +x backends/*/mcpp-ide* && ls -lR backends - - name: Build the dev tool - run: mcpp build - - name: VS Code extension - working-directory: vscode - run: | - npm ci - MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" npm run package - (cd dist/extension && npx vsce ls --no-dependencies) - - name: Gradle (xim:gradle brings its JDK) - run: xlings install gradle -y -g - - name: CLion plugin - working-directory: jetbrains - run: | - export MCPP_IDE_DEV="$(ls -t ../target/*/*/bin/mcpp-ide-dev | head -1)" MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" - gradle --no-daemon buildPlugin + path: artifacts - name: Release env: GH_TOKEN: ${{ github.token }} run: | version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" mkdir -p dist - cp "vscode/dist/mcpp-vscode-$(node -p "require('./vscode/package.json').version").vsix" dist/ - cp jetbrains/build/distributions/mcpp-clion-*.zip dist/ - (cd backends && for d in */; do tar -czf "../dist/mcpp-ide-${version}-${d%/}.tar.gz" -C "$d" .; done) - (cd dist && sha256sum * > SHA256SUMS) + cp artifacts/mcpp-vscode-vsix/*.vsix artifacts/mcpp-clion-zip/*.zip dist/ + for d in artifacts/backend-*; do + platform="${d#artifacts/backend-}" + chmod +x "$d/$platform"/* || true + tar -czf "dist/mcpp-ide-${version}-${platform}.tar.gz" -C "$d/$platform" . + done + (cd dist && sha256sum * > SHA256SUMS && cat SHA256SUMS) gh release create "v${version}" dist/* --target "$GITHUB_SHA" --title "mcpp-ide ${version}" --notes-file CHANGELOG.md diff --git a/src/bin/mockmcpp.cpp b/src/bin/mockmcpp.cpp index ff3d6f5..6f5ef6c 100644 --- a/src/bin/mockmcpp.cpp +++ b/src/bin/mockmcpp.cpp @@ -67,7 +67,7 @@ void write_record(std::string_view status) { // As mcpp does: a build asked to end leaves its record `cancelled`. void on_term() { write_record("cancelled"); - std::quick_exit(143); + std::_Exit(143); } // The failure to play: MOCK_MCPP_FAIL, else the content of `.mock-mcpp-fail` in the project (an diff --git a/vscode/src/backend/locate.ts b/vscode/src/backend/locate.ts index e3c7d3e..8724f20 100644 --- a/vscode/src/backend/locate.ts +++ b/vscode/src/backend/locate.ts @@ -50,7 +50,13 @@ export function locateBackend(options: { return { program: options.configured.trim(), source: "setting" }; } const bundled = path.join(options.extensionRoot, "bin", platformDir(platform, options.arch ?? process.arch), exe); - if (isFile(bundled)) return { program: bundled, source: "bundled" }; + if (isFile(bundled)) { + // A package's archive need not keep the mode bits. + if (platform !== "win32") { + try { fs.accessSync(bundled, fs.constants.X_OK); } catch { try { fs.chmodSync(bundled, 0o755); } catch { /* reported when it is started */ } } + } + return { program: bundled, source: "bundled" }; + } const home = options.home ?? os.homedir(); const xlingsHome = env.XLINGS_HOME; for (const candidate of [ From 7b26bb0160fc13307ca8934d1336e0c376409133 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 03:31:25 +0900 Subject: [PATCH 09/30] Translations of the adapters' strings; .xlings.json pins mcpp 2026.10.26.2; the extension-host suite also runs on the backend the package carries Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .gitignore | 1 + .xlings.json | 5 ++ spec/i18n/runtime.zh-cn.json | 91 ++++++++++++++++++++++++++++++++++++ vscode/package.json | 2 +- vscode/test/e2e/runTest.ts | 3 +- 5 files changed, 100 insertions(+), 2 deletions(-) create mode 100644 .xlings.json diff --git a/.gitignore b/.gitignore index baffece..e56e62f 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,4 @@ webui/dist/ compile_commands.json dist-upload/ jetbrains/.kotlin/ +.xlings/ diff --git a/.xlings.json b/.xlings.json new file mode 100644 index 0000000..56b60cc --- /dev/null +++ b/.xlings.json @@ -0,0 +1,5 @@ +{ + "workspace": { + "mcpp": "2026.10.26.2" + } +} diff --git a/spec/i18n/runtime.zh-cn.json b/spec/i18n/runtime.zh-cn.json index 0d2c85a..ea11c8b 100644 --- a/spec/i18n/runtime.zh-cn.json +++ b/spec/i18n/runtime.zh-cn.json @@ -1,7 +1,9 @@ { "$(cloud-download) Install a toolchain…": "$(cloud-download) 安装工具链…", "$(edit) Enter another compatible toolchain spec…": "$(edit) 输入其他兼容工具链 spec…", + "(default)": "(默认)", "(size unknown)": "(大小未知)", + "(this machine)": "(本机)", "About {0} would be freed ({1} entries).": "预计释放约 {0}({1} 个条目)。", "Accepts family, family@version, namespace, partial versions and mcpp's compatible legacy spellings": "支持 family、family@version、namespace、部分版本和 mcpp 兼容旧拼写", "Actions": "操作", @@ -14,6 +16,7 @@ "Adding {0}…": "正在添加 {0}…", "Age distribution": "按最近使用时间分布", "All": "全部", + "All packages": "全部包", "Already added": "已添加", "Already declared": "已声明", "Already within {0} GiB.": "当前已在 {0} GiB 以内。", @@ -42,6 +45,8 @@ "Build the current mcpp project and refresh the C++ Modules language service?": "是否构建当前 mcpp 工程并刷新 C++ 模块语言服务?", "Build-time dependencies (pulled at build time only, invisible at run time)": "构建期依赖(仅构建期拉取,运行时不可见)", "Bundled official index tests · commit {0}": "插件内置官方索引测试 · 提交 {0}", + "By kind": "按类别", + "By last use": "按最近使用", "Bytes and entries by how long ago they were last used.": "按最近使用时间统计的字节数与条目数。", "C++ Modules (provided by the mcpp language server extension): {0}": "C++ Modules(由 mcpp 语言服务扩展提供):{0}", "C++ Modules Deps": "C++ Modules 依赖图", @@ -58,11 +63,14 @@ "C++ Modules: show the last captured bundle": "C++ Modules:定位最近抓取的压缩包", "C++ Modules: show the module graph": "C++ Modules:查看模块图", "C++ Modules: {0}": "C++ Modules:{0}", + "Cache": "缓存", "Cache actions": "缓存操作", "Cache entry {0}": "缓存条目 {0}", "Cache statistics": "缓存统计", "Cache verification": "缓存校验", "Cache warning": "缓存告警", + "Cancel": "取消", + "Cancel the Running Job": "取消正在运行的任务", "Cancelled": "已取消", "Capability binding (equivalent to --cap)": "capability 绑定(等价于 --cap)", "Capability bindings (provider selection)": "capability 绑定(provider 选择)", @@ -71,6 +79,7 @@ "Changed from the default": "已偏离默认值", "Changing dependency groups is not supported here. Edit mcpp.toml to move the declaration.": "此处暂不支持迁移依赖分组,请编辑 mcpp.toml 移动声明。", "Changing this declaration requires a manifest edit. Copy the entry and update its dependency group in mcpp.toml.": "请复制声明并在 mcpp.toml 中调整依赖分组;已有声明不会自动迁移。", + "Check again": "重新检查", "China mirror": "国内镜像", "Choose a global default": "选择全局默认", "Choose a module source file": "选择模块源码文件", @@ -86,6 +95,7 @@ "Clean project artifacts": "清理项目产物", "Clean stale artifacts": "清理过期产物", "Clean target": "清理 target", + "Clean up": "清理", "Clear search": "清空搜索", "Click a version to aim the command above at it.": "点一个版本,上面的命令就会指向它。", "Collapse": "收起", @@ -93,6 +103,7 @@ "Collect a diagnostic report": "收集诊断报告", "Collect the global cache to a budget": "将全局缓存收敛到预算内", "Collect the shared build cache to a budget?": "将共享构建缓存收敛到预算?", + "Collect to a budget": "收敛到预算", "Collect to this budget": "收敛到此预算", "Command": "命令", "Common commands": "常用命令", @@ -104,10 +115,13 @@ "Confirm a cleanup this large": "确认如此规模的清理", "Confirm once more": "请再次确认", "Confirm one-click setup": "确认一键配置", + "Continue": "继续", "Copied": "已复制", "Copied to the clipboard.": "已复制到剪贴板。", + "Copied.": "已复制。", "Copy": "复制", "Copy Mermaid": "复制 Mermaid", + "Copy as Mermaid": "复制为 Mermaid", "Copy failed": "复制失败", "Copying…": "复制中…", "Could not add the dependency. See output for details.": "无法添加依赖,请查看输出了解详情。", @@ -121,11 +135,13 @@ "Could not write the clipboard.": "无法写入剪贴板。", "Create and open": "创建并打开", "Create the project here": "在此创建项目", + "Created {0}.": "已创建 {0}。", "Current effective toolchain": "当前有效工具链", "Current mcpp project": "当前 mcpp 工程", "Currently effective item": "当前有效项", "Custom index": "自定义索引", "Data source": "数据来源", + "Debug": "调试", "Declaration graph · dashed edges are conditional · lockfile supplies versions": "声明关系图 · 虚线为条件依赖 · 锁文件提供版本", "Declare dependency versions centrally; members inherit them with workspace = true": "集中声明依赖版本,成员用 workspace = true 继承", "Declared": "已声明", @@ -139,6 +155,7 @@ "Dependencies unavailable — click to retry": "暂时无法读取依赖,点击重试", "Dependencies will be added to this project's mcpp.toml": "依赖将添加到此项目的 mcpp.toml", "Dependency graph": "依赖图", + "Dependency name": "依赖名", "Dependency type": "依赖类型", "Deprecated": "已弃用", "Depth": "深度", @@ -155,6 +172,9 @@ "Drop entries unused for a while": "按时间丢弃长期未用的条目", "Drop every package entry from the shared cache?": "删除共享缓存中的全部包条目?", "Drop every standard library module entry from the shared cache?": "删除共享缓存中的全部标准库模块条目?", + "Drop everything": "全部删除", + "Drop package entries": "删除包条目", + "Drop standard library entries": "删除标准库条目", "Drop the entire shared build cache?": "删除整个共享构建缓存?", "Edges come from manifests and local index descriptors; lockfile versions are shown when available. This is a declaration graph, not a resolved build graph. Dashed nodes have no local dependency metadata; conditional edges may not apply to this environment.": "关系来自项目清单和本地索引描述符;有锁定版本时显示锁定版本。这是声明关系图,不代表实际构建解析结果。虚线节点缺少本地依赖元数据,条件关系可能不适用于当前环境。", "Effective target: host (mcpp shows no explicit target)": "有效 target:host(mcpp 未显示显式 target)", @@ -167,6 +187,7 @@ "Entries": "条目", "Entries unused for longer than {0} day(s) are removed. Projects that used one rebuild it.": "超过 {0} 天未使用的条目会被删除。用到它的工程会重新构建。", "Entry group": "入口分组", + "Environment Self-check": "环境自检", "Environment platform": "当前环境平台", "Environment self-check": "环境自检", "Estimated size": "估算大小", @@ -176,6 +197,7 @@ "Every mcpp project on this machine rebuilds its dependencies afterwards. Standard library module entries are kept.": "此后本机所有 mcpp 工程都会重新构建依赖。标准库模块条目保留。", "Example code": "示例代码", "Example project: {0} — built and run by the index's CI, not written for this page.": "示例工程:{0} —— 由索引的 CI 实际构建并运行过,不是为这个页面写的。", + "Executables": "可执行程序", "Exit code {0}": "退出码 {0}", "Expand importers": "展开父节点", "Expand next level": "展开下一层", @@ -186,13 +208,16 @@ "Export a diagnostic bundle": "导出诊断包", "Failed with exit code {0}": "失败,退出码 {0}", "Feature definitions": "feature 定义", + "Filter settings": "筛选设置", "Filters": "筛选", + "Find a node": "查找节点", "Find a node…": "查找节点…", "Fine-tuning of the vendored filtering policy": "vendored 过滤策略微调", "Fit": "适应窗口", "Focus": "聚焦", "Focus this result": "以此结果为焦点", "For example gcc, llvm@20.1.7, xim:gcc@16, msvc, mingw; mcpp normalises compatible spellings": "例如 gcc、llvm@20.1.7、xim:gcc@16、msvc、mingw;兼容写法由 mcpp 规范化", + "Format": "格式", "From the global default": "来自全局默认", "From the index's example source": "来自索引示例源码", "From this project's mcpp.toml, overriding the global default": "来自当前项目 mcpp.toml,覆盖全局默认", @@ -204,6 +229,7 @@ "Global default: <none>": "全局默认:<none>", "Global default: {0}": "全局默认:{0}", "Graph view": "图视图", + "Host platform": "宿主平台", "Host runtime capabilities": "主机运行时能力", "Host tool binary overrides": "host 工具二进制覆盖", "Host tools produced by the dependency (must be a bin target of that package)": "依赖产出的 host 工具(须为该包的 bin target)", @@ -212,6 +238,7 @@ "Importers depth": "父节点深度", "Include directories": "包含目录", "Incomplete entries": "不完整条目", + "Index": "索引", "Index update failed; showing the last available local snapshot.": "索引更新失败,继续显示上次可用的本地快照。", "Index updated; {0} local packages.": "索引已更新,本地共 {0} 个包。", "Index versions mcpp aggregates by family; no host payload is promised": "mcpp 按 family 聚合的索引版本;未承诺 host payload", @@ -232,6 +259,8 @@ "Large graph truncated at 120 nodes or 240 edges.": "大型依赖图已截断(最多 120 个节点或 240 条关系)。", "Largest packages": "占用最多的包", "Largest packages (top {0})": "占用最多的包(前 {0})", + "Last build": "上次构建", + "Last build: {0}, {1}": "上次构建:{0},{1}", "Last use": "最近使用", "Legacy compatibility field; new projects should use [package].standard": "旧版兼容字段;新项目请用 [package].standard", "Legend and source": "图例与源码", @@ -239,8 +268,10 @@ "Library": "库", "Library package {0}": "库包 {0}", "Library root-module convention": "库根模块约定", + "Licences": "许可证", "License": "许可", "List the shared build cache": "列出共享构建缓存", + "Loading…": "加载中…", "Locate focus": "定位焦点", "Locate selected": "定位选中", "Long dep spec: request a feature of that dependency": "长式 dep spec:请求该依赖的 feature", @@ -250,8 +281,10 @@ "Maximum dependency depth: 3": "最多展示 3 层依赖", "Mermaid source": "Mermaid 源码", "Metadata and assets compiled into the product (PE targets only)": "编译进产物的元数据与资产(仅 PE 目标)", + "Mode": "模式", "Module graph": "模块图", "More ({0})…": "其它 {0} 项…", + "Move them": "迁移", "Move them to my user settings": "移动到我的用户设置", "Move them to this workspace": "移动到当前工作区", "New mcpp project (1/2)": "新建 mcpp 工程(1/2)", @@ -274,13 +307,17 @@ "No module relationships were found for this project.": "此项目尚无模块关系。", "No other C++ language service (C/C++, clangd, ccls) is active, so no result is shown twice.": "没有其他 C++ 语言服务(C/C++、clangd、ccls)在工作,结果不会重复出现。", "No package matches this search.": "没有匹配的包。", + "No package matches.": "没有匹配的包。", + "No platform fields reported.": "未报告平台字段。", "No settings match the search": "没有匹配的设置", "No target is selected; for a target-specific install use the mcpp CLI": "不选择 target;target 专用安装请使用 mcpp CLI", "No target/ directory": "没有 target/ 目录", + "No toolchain is installed for {0}.": "{0} 尚未安装工具链。", "No verified import or header path is available locally. See the repository or index site for usage.": "本地没有可验证的模块名或头文件路径,请查看仓库或索引站的用法说明。", "No version is published for the current environment platform.": "当前环境平台没有可用的发布版本。", "No workspace folder is open": "未打开工作区文件夹", "Node actions": "节点操作", + "Not accepted ({0}); expected {1}. The default is used.": "未被接受({0});应为 {1}。已使用默认值。", "Not measured yet": "尚未测量", "Off by default: this tier runs mcpp search, which may use the network and is read from human output on a best-effort basis. Failures fall back to the local index.": "默认关闭:这一档会调用 mcpp search,可能联网,且只能从人类输出尽力解析。失败时退回本地索引。", "Official index": "官方索引", @@ -290,6 +327,7 @@ "Only C++ Modules is serving C++": "仅 C++ Modules 在提供 C++ 语言服务", "Only modified": "仅显示已修改", "Only the directory older mcpp releases wrote is removed; the current cache is kept.": "只删除旧版 mcpp 写入的目录;当前缓存保留。", + "Open": "打开", "Open an mcpp project first.": "请先打开一个 mcpp 项目。", "Open in the Settings editor": "在设置编辑器中打开", "Open logs": "打开日志", @@ -300,6 +338,7 @@ "Open source file": "打开源文件", "Open the C++ Modules settings": "打开 C++ Modules 设置", "Open the detail page for {0}": "打开 {0} 的详情页", + "Open the log": "打开日志", "Open the mcpp project and toolchain quick menu": "打开 mcpp 项目和工具链快捷菜单", "Open the repository": "打开仓库", "Opened in your browser.": "已在浏览器中打开。", @@ -312,7 +351,9 @@ "Other registries": "其它 registry", "Other registry": "其它 registry", "Override a host tool with an existing binary (skips the build)": "用已有二进制覆盖 host 工具(跳过构建)", + "Overview": "总览", "POSIX environment": "POSIX 环境", + "Pack": "打包", "Package and standard library entries go. Every mcpp project on this machine rebuilds from scratch afterwards.": "包与标准库条目都会被删除。此后本机所有 mcpp 工程都从头构建。", "Package metadata": "包元数据", "Packages": "包依赖", @@ -321,10 +362,12 @@ "Path: {0}": "路径:{0}", "Pin the xlings tool version": "固定 xlings 工具版本", "Pin tool versions": "固定工具版本", + "Platform": "平台", "Platforms and versions": "平台与版本", "Pre-v1 cache": "pre-v1 遗留缓存", "Presets": "预设", "Previous entries": "上一批入口", + "Profile": "构建配置", "Project": "项目", "Project artifacts": "工程产物", "Project artifacts are not available.": "工程产物不可用。", @@ -334,6 +377,7 @@ "Project dependency graph": "项目依赖图", "Project-level index redirection": "项目级索引重定向", "Provided by": "提供方", + "Prune by age": "按时间清理", "Read offline from {0} in the {1} index ({2} index folder(s) found).": "已从 {1} 索引离线读取 {0}(共找到 {2} 个索引目录)。", "Read-only view of what mcpp currently resolves": "只读查看 mcpp 当前解析结果", "Read-only.": "只读。", @@ -347,6 +391,7 @@ "Refresh": "刷新", "Refresh cache statistics": "刷新缓存统计", "Refresh pending": "等待刷新", + "Refresh the index": "刷新索引", "Refresh the mcpp Package Index": "刷新 mcpp 包索引", "Refresh this view": "刷新此视图", "Refreshing the mcpp Package Index…": "正在刷新 mcpp 包索引…", @@ -356,6 +401,7 @@ "Remove the cache directory of earlier mcpp releases?": "删除旧版 mcpp 的缓存目录?", "Remove the pre-v1 cache": "清理 pre-v1 遗留缓存", "Remove the whole target/ directory?": "删除整个 target/ 目录?", + "Renamed settings": "已改名的设置", "Repository": "仓库", "Reread locally": "重新读取本地索引", "Reset": "重置", @@ -365,9 +411,12 @@ "Resolved {0}": "已解析 {0}", "Resolved —": "已解析 —", "Restart language service": "重启语言服务", + "Restart the language server": "重启语言服务", "Restart the semantic engine": "重启语义引擎", + "Result": "结果", "Result: {0}": "结果:{0}", "Retry reading details": "重新读取详情", + "Reveal": "在文件管理器中显示", "Root: {0}": "根目录:{0}", "Run": "运行", "Run the build tool in a terminal": "在终端运行构建工具", @@ -386,9 +435,11 @@ "Searching all registries failed (exit {0}); showing the local index only.": "搜索全部 registry 失败(退出码 {0});只显示本地索引。", "Searching all registries…": "正在搜索全部 registry…", "Searching other registries…": "正在搜索其它 registry…", + "Searching…": "搜索中…", "Select a node to explore its relationships.": "选择节点查看关联。", "Select an mcpp project before adding this library.": "请先选择 mcpp 项目,再添加此库。", "Select analysis context": "重选分析上下文", + "Select the build target": "选择构建目标", "Select the global default toolchain": "选择全局默认工具链", "Selected": "选中", "Selected node": "已选节点", @@ -405,6 +456,7 @@ "Show cache entry details for {0}": "查看缓存条目 {0} 的详情", "Show output": "查看输出", "Show running tasks": "显示正在运行的任务", + "Show the whole graph": "显示完整的图", "Show toolchains": "查看工具链", "Simulates mcpp cache gc --max-size: the estimate is a local projection, so mcpp's own policy decides in the end.": "模拟 mcpp cache gc --max-size:这里的估算只是本地推算,最终仍以 mcpp 自身的策略为准。", "Size": "大小", @@ -421,11 +473,13 @@ "Table form: contributes the package's own macros when activated": "表形式:激活时贡献包自有宏", "Table form: feature-gated source globs": "表形式:feature 门控的源 glob", "Table form: requires a capability": "表形式:需要 capability", + "Takes effect after a restart.": "重启后生效。", "Takes effect on the next build": "下次构建时生效", "Takes effect on the next clean": "下次清理时生效", "Target": "目标", "Target project": "目标项目", "Targets": "目标", + "Targets and Platforms": "目标与平台", "Task arguments: {0}": "任务参数:{0}", "Test": "测试", "Tests": "测试", @@ -443,6 +497,8 @@ "The mcpp build failed (exit code {0}); the C++ Modules language service re-read the existing build description.": "mcpp 构建失败(退出码 {0});C++ 模块语言服务已重新读取现有构建描述。", "The mcpp build finished; the C++ Modules language service has been refreshed.": "mcpp 构建完成,C++ 模块语言服务已刷新。", "The mcpp global default is now {0} + host target. Cleaning the old toolchain artifacts and rebuilding is recommended.": "mcpp 全局默认已更新为 {0} + host target。建议清理旧工具链产物后重新构建。", + "The mcpp-ide backend ended.": "mcpp-ide 后端已结束。", + "The mcpp-ide backend was not found. Install it with `xlings install mcpp-ide`, or set mcpp.ide.backendPath.": "未找到 mcpp-ide 后端。请用 `xlings install mcpp-ide` 安装,或设置 mcpp.ide.backendPath。", "The package descriptor is missing. Reread the local index.": "包描述不存在,请重新读取本地索引。", "The program did not build; see the task terminal for the compiler output.": "程序未构建成功;编译器输出见任务终端。", "The project currently overrides the global default; this only changes the current mcpp global configuration": "项目当前覆盖全局默认;这里只修改 mcpp 当前全局配置", @@ -456,6 +512,7 @@ "The project name must not end with . (unsupported on Windows).": "项目名不能以 . 结尾(Windows 不支持)", "The project name must not start with -, or mcpp would read it as a command-line option.": "项目名不能以 - 开头,否则会被 mcpp 解析为命令行选项", "The project root sits below the VS Code folder; the real build resolution is whatever mcpp reports": "当前工程根位于 VS Code 文件夹子目录;实际构建解析以 mcpp 为准", + "The project's name, which is also its directory": "工程名,也是它的目录名", "The same figures are listed as text next to each bar.": "每个条形图旁边以文字列出了同样的数字。", "The setting could not be written; the toggle was not saved.": "设置写入失败;开关没有保存。", "The shared build cache could not be read.": "无法读取共享构建缓存。", @@ -465,12 +522,14 @@ "The source graph is incomplete. Refresh after indexing finishes.": "数据尚不完整,可在索引完成后刷新。", "The source graph is incomplete. Some modules may be omitted.": "源图数据不完整,部分模块可能尚未包含。", "The target axis is shown read-only; to select a target use the mcpp CLI": "target 轴只读展示;选择 target 请使用 mcpp CLI", + "The target build, run, test, debug and pack use": "构建、运行、测试、调试与打包使用的目标", "The version is required: mcpp accepts an exact version only.": "必须指定版本:mcpp 只接受精确版本。", "The workspace is not trusted; mcpp itself was not probed.": "工作区未受信任;未探测 mcpp 本身。", "The workspace is not trusted; the other registries were not searched.": "工作区未受信任;未搜索其他 registry。", "The {0} largest cache labels, by bytes.": "按字节数排名的前 {0} 个缓存标签。", "There is no pre-v1 cache to remove.": "没有可清理的 pre-v1 缓存。", "They answer the same C++ files, so results appear twice. Click to turn their C++ language features off; C++ Modules asks whether for this workspace or everywhere.": "它们也在处理同一批 C++ 文件,结果会出现两次。点击即可关闭它们的 C++ 语言功能;C++ Modules 会询问只对本工作区还是对所有地方生效。", + "This command is not available in this IDE.": "此命令在当前 IDE 中不可用。", "This deletes every build directory of this project. The next build starts from scratch. The shared build cache is not touched.": "这会删除本工程的全部构建目录,下次构建从头开始。共享构建缓存不受影响。", "This dependency name is ambiguous. Use a qualified package name in mcpp.toml.": "此依赖名称有歧义,请在 mcpp.toml 中使用完整包名。", "This descriptor declares no dependencies.": "此描述符没有声明依赖。", @@ -480,6 +539,7 @@ "This is a search preview. Set an index path containing this package to read its complete details.": "这是搜索预览。将索引路径设置为包含此包的目录后,可读取完整详情。", "This is the current-directory view; overrides from the project or a parent configuration are decided by the actual build": "当前目录视图;项目或父级配置的覆盖以实际构建为准", "This is the current-directory view; the value mcpp build resolves is authoritative": "当前目录视图;实际生效值以 mcpp build 解析为准", + "This machine: {0}": "本机:{0}", "This mcpp build does not recognise that command; update mcpp or check the spelling.": "此 mcpp 版本不认识该命令;请升级 mcpp 或检查拼写。", "This package has no test project in the index, so there is no example to show.": "此包在索引里没有示例工程,因此没有示例可显示。", "This package is not in the local index any more.": "此包已不在本地索引中。", @@ -498,6 +558,7 @@ "Toolchain": "工具链", "Toolchain managed by mcpp": "mcpp 管理的工具链", "Toolchain {0} installed. Choose a global default from the latest list?": "工具链 {0} 安装完成。是否从最新列表中选择全局默认?", + "Toolchains": "工具链", "Trust this workspace to run mcpp and add dependencies.": "信任此工作区后,才能运行 mcpp 和添加依赖。", "Unavailable": "暂无元数据", "Unexpected error: {0}": "发生未预期错误:{0}", @@ -513,6 +574,7 @@ "User settings": "用户设置", "VS Code could not open {0}. The link is on your clipboard.": "VS Code 无法打开 {0},链接已复制到剪贴板。", "Values shown for {0}": "以下值适用于 {0}", + "Verify": "校验", "Verify the cache": "校验缓存", "Verify the shared build cache": "校验共享构建缓存", "Verify the shared cache": "校验共享缓存", @@ -525,6 +587,7 @@ "View limit reached. Focus a node to explore its dependencies.": "已达到当前视图上限,可聚焦节点继续查看。", "View options": "视图", "What the descriptor declares. The resolved version lives in a project's mcpp.lock, not here.": "这里显示描述符声明的依赖。解析后的版本在工程的 mcpp.lock 里,不在这里。", + "What to produce": "要生成的内容", "Working directory: {0}": "工作目录:{0}", "Workspace": "工作区", "Workspace folder": "工作区文件夹", @@ -535,11 +598,19 @@ "a project's name is one directory name: {0}": "工程名必须是单个目录名:{0}", "added": "已添加", "build": "构建", + "build, run, test, debug and pack use it": "构建、运行、测试、调试与打包都使用它", + "by name": "按名称", + "by versions": "按版本数", + "change": "更改", "conditional": "条件", "convention {0}": "约定 {0}", "dev dependency": "dev 依赖", + "every index": "所有索引", "git · {0}": "git · {0}", + "host conventions": "宿主约定", "host default": "host 默认", + "host platform": "宿主平台", + "in {0} entries": "共 {0} 个条目", "index": "索引", "latest {0}": "最新 {0}", "mcpp CLI operation failed: {0}": "mcpp CLI 操作失败:{0}", @@ -556,6 +627,7 @@ "mcpp cache list failed (exit {0})": "mcpp cache list 失败(退出码 {0})", "mcpp cache verify failed with exit code {0}": "mcpp cache verify 失败,退出码 {0}", "mcpp clean --dry-run": "mcpp clean --dry-run", + "mcpp could not answer": "mcpp 未能回答", "mcpp decides whether the compiler prefix is a valid triple; when it is, it may download a larger toolchain package for that target.": "mcpp 会判断编译器前缀是否为有效 triple;有效时可能下载对应 target 的较大工具链包。", "mcpp does not download or install MSVC; it detects Visual Studio and points to the official installation guide when it is missing.": "mcpp 不会下载或安装 MSVC;它会检测 Visual Studio,并在缺失时给出官方安装指引。", "mcpp drops least-recently-used entries until the cache fits. Projects that used a dropped entry rebuild it.": "mcpp 按最近最少使用的顺序删除条目,直到缓存符合预算。用到被删条目的工程会重新构建。", @@ -571,6 +643,7 @@ "mcpp list toolchain for this directory": "mcpp list 当前目录工具链", "mcpp listed no usable toolchain; see the raw result in the mcpp output channel.": "mcpp 没有列出可用工具链;请查看 mcpp 输出频道中的原始结果。", "mcpp new {0} failed (exit code {1}). See the mcpp output channel.": "mcpp new {0} 失败(退出码 {1})。请查看 mcpp 输出频道。", + "mcpp new {0}: {1}": "mcpp new {0}:{1}", "mcpp normalises the compatible spelling and may download a larger toolchain package for that target.": "mcpp 会规范化兼容写法,并可能下载对应 target 的较大工具链包。", "mcpp pack packaging configuration": "mcpp pack 打包配置", "mcpp rejected the command line; check the arguments and run it from the project root.": "mcpp 拒绝了命令行;请检查参数,并在工程根目录运行。", @@ -587,6 +660,7 @@ "mcpp {0} at {1}": "mcpp {0},位于 {1}", "mcpp {0} failed with exit code {1}": "mcpp {0} 失败,退出码 {1}", "mcpp {0} predates the control contract ({1}): builds run without events, records or launch descriptors": "mcpp {0} 早于控制契约({1}):构建不提供事件、结果记录与启动描述", + "mcpp {0}: {1}": "mcpp {0}:{1}", "mcpp.toml could not be read": "无法读取 mcpp.toml", "mcpp: Build": "mcpp: 构建", "mcpp: Clean": "mcpp: 清理", @@ -604,21 +678,31 @@ "mcppls {0} predates mcpp's result record: a build does not refresh it. Update mcppls to {1} or later.": "mcppls {0} 早于 mcpp 的结果记录:构建后它不会刷新。请将 mcppls 更新到 {1} 或更新版本。", "more than {0} day(s)": "超过 {0} 天", "more than {0} day(s) ago": "超过 {0} 天前", + "needs attention": "需要处理", "no such package": "没有这个包", + "none": "无", "not read yet": "尚未读取", + "older than {0} days": "超过 {0} 天", + "one per line": "每行一个", "openkal-compat": "openkal-compat", "openkal-ecosystem": "openkal-ecosystem", "other registry": "其它 registry", "path · {0}": "路径 · {0}", + "platform not reported by this mcpp": "此版本 mcpp 未报告平台", + "reported after the first build": "首次构建后报告", "resolved {0}": "已解析 {0}", "runs after the job in progress": "在当前任务结束后运行", + "selected": "已选择", "the control contract is available": "控制契约可用", + "the mcpp-ide backend is not running": "mcpp-ide 后端未运行", "the program could not be built": "程序未能构建", + "the project's default": "工程默认值", "the workspace is not trusted": "工作区未受信任", "the workspace is not trusted: mcpp runs with effects denied": "工作区未受信任:mcpp 在禁止副作用的情况下运行", "the workspace is trusted": "工作区已受信任", "this action needs a trusted workspace": "此操作需要受信任的工作区", "this action was not confirmed": "此操作未经确认", + "this machine": "本机", "this platform": "当前平台", "this program runs through {0}; the debugger starts {0} and reads the program's symbols when it is loaded": "此程序经由 {0} 运行;调试器启动 {0},并在程序加载时读取其符号", "under {0} day(s)": "少于 {0} 天", @@ -629,6 +713,7 @@ "xlings at {0}": "xlings,位于 {0}", "xlings is not on PATH; mcpp uses the one it bundles": "PATH 中没有 xlings;mcpp 使用其自带的 xlings", "{0}": "{0}", + "{0} and {1} node(s) around it": "{0} 及其周围 {1} 个节点", "{0} cache entries are incomplete; run mcpp cache verify to see which ones.": "有 {0} 个缓存条目不完整;运行 mcpp cache verify 可查看具体是哪些。", "{0} descriptor(s) from {1} local index folder(s): {2}. Read offline.": "从 {1} 个本地索引目录读到 {0} 个描述符:{2}。离线读取。", "{0} dev": "{0} 个 dev", @@ -640,9 +725,14 @@ "{0} finished.": "{0} 已完成。", "{0} further package(s) came from the other registries.": "另有 {0} 个包来自其它 registry。", "{0} in the shared cache": "共享缓存中 {0}", + "{0} job(s) running": "{0} 个任务正在运行", + "{0} nodes, {1} edges": "{0} 个节点,{1} 条边", + "{0} nodes: choose one to see its neighbourhood, or show the whole graph.": "共 {0} 个节点:选择一个查看其周围,或显示完整的图。", "{0} of {1} packages": "{0} / {1} 个包", + "{0} packages": "{0} 个包", "{0} problem(s)": "{0} 个问题", "{0} source file(s)": "{0} 个源文件", + "{0} step(s) around": "周围 {0} 层", "{0} was cancelled.": "{0}已取消。", "{0} {1}": "{0} {1}", "{0} {1} is older than the verified range ({2}); the capability probe will hide what it cannot do.": "{0} {1} 低于已验证范围({2});能力探测会隐藏它做不到的部分。", @@ -658,6 +748,7 @@ "{0}{1}": "{0}{1}", "{0}–{1} day(s)": "{0}–{1} 天", "{0}–{1} day(s) ago": "{0}–{1} 天前", + "{0}–{1} days": "{0}–{1} 天", "…": "…", "✓ Has examples": "✓ 有示例" } diff --git a/vscode/package.json b/vscode/package.json index b7ef3aa..a1c0cb7 100644 --- a/vscode/package.json +++ b/vscode/package.json @@ -285,7 +285,7 @@ "compile": "tsc -p tsconfig.json", "gen": "cd .. && mcpp run mcpp-ide-dev -- gen vscode --out vscode/dist/extension --stage", "test": "npm run compile && node --test \"out/test/unit/**/*.test.js\" && node --test \"../webui/tests/*.test.js\"", - "test:e2e": "npm run compile && npm run gen && node out/test/e2e/runTest.js", + "test:e2e": "npm run compile && npm run gen && node out/test/e2e/runTest.js && MCPP_E2E_BUNDLED=1 node out/test/e2e/runTest.js", "package": "npm run compile && npm run gen && cd dist/extension && vsce package --no-dependencies -o ../mcpp-vscode-$npm_package_version.vsix", "check:webui": "tsc -p ../webui/tsconfig.json" }, diff --git a/vscode/test/e2e/runTest.ts b/vscode/test/e2e/runTest.ts index b0a84c4..d2ba515 100644 --- a/vscode/test/e2e/runTest.ts +++ b/vscode/test/e2e/runTest.ts @@ -21,8 +21,9 @@ async function main(): Promise<void> { fs.writeFileSync(path.join(workspace, "tests", "test_smoke.cpp"), "int main() { return 0; }\n"); const user = path.join(temp, "user-data", "User"); fs.mkdirSync(user, { recursive: true }); + // MCPP_E2E_BUNDLED: the backend the staged extension carries (bin/<platform>/), as a user gets it. fs.writeFileSync(path.join(user, "settings.json"), JSON.stringify({ - "mcpp.ide.backendPath": backend, + ...(process.env.MCPP_E2E_BUNDLED ? {} : { "mcpp.ide.backendPath": backend }), "mcpp.path": mock, "security.workspace.trust.enabled": false, })); From b0ca4e1bd4c56b5859be1af96a8283be9103308a Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 03:45:00 +0900 Subject: [PATCH 10/30] Build on each system as mcpp itself does: GCC on Linux, the xlings LLVM on macOS and Windows; the arm64 Linux release program is cross-built on x86_64 `--target aarch64-macos` linked without libSystem and `--target x86_64-windows-gnu` read the runner's MinGW libstdc++ with clang; the native targets with [toolchain] macos/windows are what mcpp's own build uses. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/workflows/ci.yml | 40 ++++++++++++++++++++++++++++------------ mcpp.toml | 14 ++++++++++++++ 2 files changed, 42 insertions(+), 12 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69d328f..c0083c9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -30,11 +30,13 @@ jobs: strategy: fail-fast: false matrix: + # `releases`: the release programs a leg builds, as `<platform>=<target>` (empty target: this + # system). The arm64 Linux program is cross-built on x86_64, where musl-gcc's cross payload is. include: - - { os: ubuntu-24.04, platform: linux-x64, target: '', release: '--target x86_64-linux-musl', llvm: 'false', exe: mcpp-ide } - - { os: ubuntu-24.04-arm, platform: linux-arm64, target: '', release: '--target aarch64-linux-musl', llvm: 'false', exe: mcpp-ide } - - { os: macos-14, platform: darwin-arm64, target: '--target aarch64-macos', release: '--target aarch64-macos', llvm: 'true', exe: mcpp-ide } - - { os: windows-2022, platform: win32-x64, target: '--target x86_64-windows-gnu', release: '--target x86_64-windows-gnu', llvm: 'true', exe: mcpp-ide.exe } + - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', releases: 'linux-x64=x86_64-linux-musl linux-arm64=aarch64-linux-musl' } + - { os: ubuntu-24.04-arm, platform: linux-arm64, llvm: 'false', releases: '' } + - { os: macos-14, platform: darwin-arm64, llvm: 'true', releases: 'darwin-arm64=' } + - { os: windows-2022, platform: win32-x64, llvm: 'true', releases: 'win32-x64=' } defaults: run: shell: bash @@ -44,18 +46,32 @@ jobs: with: llvm: ${{ matrix.llvm }} - name: Build - run: mcpp build ${{ matrix.target }} + run: mcpp build - name: Test - run: mcpp test ${{ matrix.target }} + run: mcpp test - name: Every string has its translation - run: mcpp run ${{ matrix.target }} mcpp-ide-dev -- check-i18n - - name: Release program + run: mcpp run mcpp-ide-dev -- check-i18n + - name: Release programs + if: matrix.releases != '' run: | - mcpp build --release ${{ matrix.release }} - mkdir -p "out/${{ matrix.platform }}" - cp "$(ls -t target/*/*/bin/${{ matrix.exe }} | head -1)" "out/${{ matrix.platform }}/" - "out/${{ matrix.platform }}/${{ matrix.exe }}" --version + set -euo pipefail + for entry in ${{ matrix.releases }}; do + platform="${entry%%=*}" target="${entry#*=}" + case "$platform" in win32-*) exe=mcpp-ide.exe ;; *) exe=mcpp-ide ;; esac + if [ -n "$target" ]; then + mcpp build --release --target "$target" + built="$(ls -t target/"$target"/*/bin/$exe | head -1)" + else + mcpp build --release + built="$(ls -t target/*/*/bin/$exe | head -1)" + fi + mkdir -p "out/$platform" + cp "$built" "out/$platform/" + file "out/$platform/$exe" 2>/dev/null || true + done + case "${{ matrix.platform }}" in win32-*) out/win32-x64/mcpp-ide.exe --version ;; *) "out/${{ matrix.platform }}/mcpp-ide" --version ;; esac - uses: actions/upload-artifact@v5 + if: matrix.releases != '' with: name: backend-${{ matrix.platform }} path: out diff --git a/mcpp.toml b/mcpp.toml index 0cd809b..9c6364f 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -21,6 +21,20 @@ standard = "c++23" modules = true import_std = true +# As mcpp itself builds: GCC on Linux, the xlings LLVM on macOS and Windows, each for its own +# system. The Linux programs the editor packages carry are static musl ones, cross-built for arm64 +# from x86_64 as well (the target table pins musl-gcc for both rows). +[toolchain] +default = "gcc@16.1.0" +macos = "llvm@23.1.3" +windows = "llvm@23.1.3" + +[target.x86_64-linux-musl] +linkage = "static" + +[target.aarch64-linux-musl] +linkage = "static" + [build] sources = ["src/*.cppm"] macos_deployment_target = "12.0" From 125b035e03f39ac7a0086714deff3de498f5c751 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 03:55:41 +0900 Subject: [PATCH 11/30] The mock mcpp writes its streams as bytes through mcpplibs.os; fixtures are byte-exact (.gitattributes); an arm64 Linux machine builds its own programs with LLVM On Windows a C++ stream wrote mcpp's output translated, and the backend's tests there read no envelope; mcpp's own output is bytes. test_jobs prints what it received when the envelope is missing. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .gitattributes | 4 ++++ mcpp.toml | 4 ++++ src/bin/mockmcpp.cpp | 40 ++++++++++++++++++++++++---------------- tests/test_jobs.cpp | 4 ++++ 4 files changed, 36 insertions(+), 16 deletions(-) create mode 100644 .gitattributes diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..8909cc8 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,4 @@ +# Text is LF everywhere; the golden fixtures are mcpp's bytes, compared and replayed exactly. +* text=auto eol=lf +protocol/fixtures/** -text +*.png binary diff --git a/mcpp.toml b/mcpp.toml index 9c6364f..aa0f413 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -29,6 +29,10 @@ default = "gcc@16.1.0" macos = "llvm@23.1.3" windows = "llvm@23.1.3" +# An arm64 Linux machine's own programs: the xlings gcc payload has no aarch64-hosted C++ frontend. +[target.aarch64-linux-gnu] +toolchain = "llvm@23.1.3" + [target.x86_64-linux-musl] linkage = "static" diff --git a/src/bin/mockmcpp.cpp b/src/bin/mockmcpp.cpp index 6f5ef6c..39fb705 100644 --- a/src/bin/mockmcpp.cpp +++ b/src/bin/mockmcpp.cpp @@ -25,6 +25,14 @@ std::string slurp(const std::filesystem::path& p) { return std::string(std::istreambuf_iterator<char>(in), {}); } +// What mcpp prints, as bytes: the standard streams of mcpplibs.os translate nothing (a C++ stream on +// Windows writes every \n as \r\n), and each write is complete when it returns. +void out(std::string_view text) { + (void)mcpplibs::os::stdio::write_output(text); + (void)mcpplibs::os::stdio::flush_output(); +} +void err(std::string_view text) { (void)mcpplibs::os::stdio::write_error(text); } + std::string replace_all(std::string s, std::string_view from, std::string_view to) { for (auto pos = s.find(from); pos != std::string::npos; pos = s.find(from, pos + to.size())) s.replace(pos, from.size(), to); return s; @@ -84,15 +92,15 @@ int build(bool message) { const auto fail = failure(); std::string stream = fixture(fail == "build" ? "build-failed.ndjson" : fail == "manifest" ? "build-manifest-error.ndjson" : "build-ok.ndjson"); - std::println(std::cerr, " Compiling app v0.1.0 (.)"); + err(" Compiling app v0.1.0 (.)\n"); if (const auto slow = env("MOCK_MCPP_SLOW_MS"); !slow.empty()) { write_record("running"); // A request to end (SIGTERM, a console control event) is taken over and answered as mcpp // answers it: the record says `cancelled` (mcpplibs.os.interrupt). if (mcpplibs::os::interrupt::wait(std::chrono::milliseconds(std::stoi(slow)))) on_term(); } - if (message) std::cout << stream << std::flush; - if (fail.empty()) { write_record("ok"); std::println(std::cerr, " Finished dev [unoptimized + debuginfo] in 0.01s"); return 0; } + if (message) out(stream); + if (fail.empty()) { write_record("ok"); err(" Finished dev [unoptimized + debuginfo] in 0.01s\n"); return 0; } if (fail == "build") write_record("failed"); return 1; } @@ -109,28 +117,28 @@ int main(int argc, char** argv) { auto has = [&](std::string_view a) { return std::ranges::find(args, a) != args.end(); }; auto first = [&](std::size_t i) { return i < args.size() ? args[i] : std::string{}; }; if (args.empty()) return 2; - if (first(0) == "--version") { std::cout << fixture("version.txt"); return 0; } - if (first(0) == "--protocol-version") { std::cout << fixture("protocol-version.json"); return 0; } + if (first(0) == "--version") { out(fixture("version.txt")); return 0; } + if (first(0) == "--protocol-version") { out(fixture("protocol-version.json")); return 0; } if (first(0) == "build") return build(has("--message-format")); - if (first(0) == "test") { std::cout << fixture(has("--list") ? "test-list.ndjson" : "test.ndjson"); return 0; } - if (first(0) == "run" && has("--print-launch")) { std::cout << fixture("launch.json"); return 0; } - if (first(0) == "search") { std::cout << fixture("search.json"); return 0; } - if (first(0) == "index" && first(1) == "list") { std::cout << fixture("index-list.json"); return 0; } - if (first(0) == "pack" && has("--list-formats")) { std::cout << fixture("pack-formats.json"); return 0; } - if (first(0) == "toolchain" && first(1) == "list") { std::cout << fixture("toolchain-list.json"); return 0; } - if (first(0) == "cache" && first(1) == "list") { std::cout << fixture("cache-list.json"); return 0; } + if (first(0) == "test") { out(fixture(has("--list") ? "test-list.ndjson" : "test.ndjson")); return 0; } + if (first(0) == "run" && has("--print-launch")) { out(fixture("launch.json")); return 0; } + if (first(0) == "search") { out(fixture("search.json")); return 0; } + if (first(0) == "index" && first(1) == "list") { out(fixture("index-list.json")); return 0; } + if (first(0) == "pack" && has("--list-formats")) { out(fixture("pack-formats.json")); return 0; } + if (first(0) == "toolchain" && first(1) == "list") { out(fixture("toolchain-list.json")); return 0; } + if (first(0) == "cache" && first(1) == "list") { out(fixture("cache-list.json")); return 0; } if (first(0) == "emit") { if (failure() == "manifest") { - std::cout << replace_all(fixture("build-manifest-error.ndjson"), "\"mcpp.build\"", "\"mcpp.build-database\""); + out(replace_all(fixture("build-manifest-error.ndjson"), "\"mcpp.build\"", "\"mcpp.build-database\"")); return 1; } - std::cout << fixture("build-database.json"); + out(fixture("build-database.json")); return 0; } - if (first(0) == "self" && first(1) == "env") { std::cout << fixture("self-env.json"); return 0; } + if (first(0) == "self" && first(1) == "env") { out(fixture("self-env.json")); return 0; } // Everything else is a command a person reads: say what ran. std::string line; for (const auto& a : args) { if (!line.empty()) line += ' '; line += a; } - std::println(std::cerr, "mock mcpp: {}", line); + err(std::format("mock mcpp: {}\n", line)); return 0; } diff --git a/tests/test_jobs.cpp b/tests/test_jobs.cpp index 1ad624c..5dfd028 100644 --- a/tests/test_jobs.cpp +++ b/tests/test_jobs.cpp @@ -44,6 +44,10 @@ int main() { CHECK(seen.finished.contains(ok)); CHECK(seen.finished[ok]["status"] == "ok"); CHECK(!seen.records.empty()); + if (!seen.finished[ok].contains("envelope")) { + std::println(std::cerr, "no envelope; the summary: {}", seen.finished[ok].dump()); + for (const auto& r : seen.records) std::println(std::cerr, "record: {}", r.dump().substr(0, 200)); + } CHECK(seen.finished[ok].contains("envelope")); } From f9e7c78d7ac3265e7387b65822fd45cf498efb04 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 04:12:33 +0900 Subject: [PATCH 12/30] The mock mcpp puts paths into its JSON escaped; the package store's cache is per architecture A Windows runner's HOME holds backslashes, which made every fixture line naming the home invalid JSON there. An arm64 Linux runner restored the x86_64 store (its ninja could not start): runner.os is Linux on both. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/actions/setup-mcpp/action.yml | 4 ++-- src/bin/mockmcpp.cpp | 15 +++++++++++++-- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/.github/actions/setup-mcpp/action.yml b/.github/actions/setup-mcpp/action.yml index dc83a77..ed417d9 100644 --- a/.github/actions/setup-mcpp/action.yml +++ b/.github/actions/setup-mcpp/action.yml @@ -33,8 +33,8 @@ runs: uses: actions/cache@v5 with: path: ~/.mcpp/registry/data/xpkgs - key: mcpp-xpkgs-${{ runner.os }}-${{ env.MCPP_VERSION }}-${{ hashFiles('mcpp.toml', 'mcpp.lock') }} - restore-keys: mcpp-xpkgs-${{ runner.os }}-${{ env.MCPP_VERSION }}- + key: mcpp-xpkgs-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_VERSION }}-${{ hashFiles('mcpp.toml', 'mcpp.lock') }} + restore-keys: mcpp-xpkgs-${{ runner.os }}-${{ runner.arch }}-${{ env.MCPP_VERSION }}- - name: Install mcpp shell: bash run: | diff --git a/src/bin/mockmcpp.cpp b/src/bin/mockmcpp.cpp index 39fb705..b3b1c42 100644 --- a/src/bin/mockmcpp.cpp +++ b/src/bin/mockmcpp.cpp @@ -50,12 +50,23 @@ std::filesystem::path fixtures_dir() { return {}; } +// A path as it stands inside a JSON string of a fixture: `/`-separated, and escaped. (A Windows +// runner's HOME is `C:\Users\...`, whose backslashes are escapes inside JSON.) +std::string json_path(const std::filesystem::path& p) { + std::string out; + for (char c : p.generic_string()) { + if (c == '\\' || c == '"') out += '\\'; + out += c; + } + return out; +} + std::string fixture(std::string_view name) { const auto dir = fixtures_dir(); auto text = slurp(std::filesystem::path(dir) / name); std::error_code ec; - text = replace_all(std::move(text), "@ROOT@", std::filesystem::current_path(ec).generic_string()); - text = replace_all(std::move(text), "@HOME@", env("HOME")); + text = replace_all(std::move(text), "@ROOT@", json_path(std::filesystem::current_path(ec))); + text = replace_all(std::move(text), "@HOME@", json_path(env("HOME"))); return text; } From 2efcbdb17b24f5ee6b4ca893daf0ac8dffa44df1 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 04:22:05 +0900 Subject: [PATCH 13/30] test_jobs: the record of a cancelled build is `cancelled` where the system delivers a request to end; on Windows the build is ended outright and its record is never `ok` Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- tests/test_jobs.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/test_jobs.cpp b/tests/test_jobs.cpp index 5dfd028..6238642 100644 --- a/tests/test_jobs.cpp +++ b/tests/test_jobs.cpp @@ -71,8 +71,12 @@ int main() { std::lock_guard g(seen.lock); CHECK(seen.finished[slow]["status"] == "cancelled"); } + // mcpp leaves its record `cancelled` when the system delivers the request to end (SIGTERM). On + // Windows the program is ended outright (openkal-windows: TerminateProcess), so the record is + // the last one mcpp wrote, never `ok`. const auto record = testsupport::read(root / "target" / ".last-result.json"); - CHECK(record.find("\"cancelled\"") != std::string::npos); + if (mcpplibs::os::host() == mcpplibs::os::platform::windows) CHECK(record.find("\"ok\"") == std::string::npos); + else CHECK(record.find("\"cancelled\"") != std::string::npos); std::error_code ec; std::filesystem::remove_all(root, ec); From fdb3deff6d6c6b2dcccb80d83ec35fdb7f9f069d Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 04:48:11 +0900 Subject: [PATCH 14/30] One package for every system: the backend as an ok-image bundle run by the okrun carried per system; --pkg-format where mcpp offers it MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both adapters start, in order: mcpp.ide.backendPath (a program, or an .okb run by okrun); backend/mcpp-ide.okb run by backend/okrun/<os>-<arch>/okrun, else by okrun on PATH (mcpp design 2026-10-28 part 2 §15); bin/<platform>/, the program per system packages carry until the bundle is built; then an installed mcpp-ide. mcpp-ide-dev gen vscode --stage and the plugin's sandbox take --okb/MCPP_IDE_OKB and --okrun/MCPP_IDE_OKRUN. CI opens both packages on Linux x64 and arm64, macOS and Windows and starts what each carries for that system (.github/scripts/check-package.sh): one bundle and its okrun once they exist, the system's program until then. The backend reads `mcpp pack --help` once: the package format goes as --pkg-format where mcpp offers it (SPEC-014), else --format; the pack panel's closures are SPEC-014's and linkages appear where mcpp takes them (protocol: pack/start's pkgFormat and linkage; pack/formats' modes and linkages; the captured help is a fixture). Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/scripts/check-package.sh | 46 ++++++++++ .github/workflows/ci.yml | 26 ++++++ CHANGELOG.md | 4 + README.md | 5 +- README.zh-CN.md | 3 +- docs/architecture.md | 13 +++ jetbrains/README.md | 8 +- jetbrains/build.gradle.kts | 14 ++- .../mcppcommunity/mcppclion/McppSession.kt | 4 +- .../mcppcommunity/mcppclion/backend/Locate.kt | 86 +++++++++++++------ .../mcppcommunity/mcppclion/BackendTest.kt | 19 ++++ protocol/fixtures/pack-help.txt | 25 ++++++ protocol/protocol.schema.json | 11 ++- spec/i18n/runtime.zh-cn.json | 1 + src/bin/dev.cpp | 34 ++++++-- src/bin/mockmcpp.cpp | 1 + src/mcpp.cppm | 2 + src/server.cppm | 42 ++++++++- tests/test_protocol.cpp | 5 ++ vscode/README.md | 5 +- vscode/src/backend/locate.ts | 65 ++++++++++---- vscode/src/session.ts | 3 +- vscode/test/unit/locate.test.ts | 26 +++++- webui/js/panels/pack.js | 12 ++- 24 files changed, 383 insertions(+), 77 deletions(-) create mode 100755 .github/scripts/check-package.sh create mode 100644 protocol/fixtures/pack-help.txt diff --git a/.github/scripts/check-package.sh b/.github/scripts/check-package.sh new file mode 100755 index 0000000..bae7452 --- /dev/null +++ b/.github/scripts/check-package.sh @@ -0,0 +1,46 @@ +#!/usr/bin/env bash +# check-package.sh <package> <root inside the archive> +# +# What an editor package carries of the backend, checked on the system this runs on (CI runs it on +# every system): with the ok-image bundle (mcpp design 2026-10-28 part 2 §15), exactly one +# backend/mcpp-ide.okb, an okrun for every system and architecture, and the one for this system +# starting the bundle; until the bundle is built, a program for every system, and the one for this +# system answering. +set -euo pipefail +package="$1" prefix="$2" +dir="$(mktemp -d)" +trap 'rm -rf "$dir"' EXIT +unzip -q "$package" -d "$dir" +root="$dir/$prefix" + +case "$(uname -s)" in Linux) os=linux vs=linux ;; Darwin) os=macos vs=darwin ;; *) os=windows vs=win32 ;; esac +case "$(uname -m)" in x86_64|amd64|AMD64) arch=x86_64 va=x64 ;; aarch64|arm64|ARM64) arch=aarch64 va=arm64 ;; *) arch="$(uname -m)" va="$arch" ;; esac +exe=""; [ "$os" = windows ] && exe=".exe" + +answers() { # <argv...>: the backend says who it is + "$@" --version | tee /dev/stderr | grep -q '^mcpp-ide ' +} + +okbs="$(find "$root" -name '*.okb' | wc -l | tr -d ' ')" +if [ "$okbs" != 0 ]; then + [ "$okbs" = 1 ] || { echo "::error::$package carries $okbs ok-image bundles; one is expected"; exit 1; } + [ -f "$root/backend/mcpp-ide.okb" ] || { echo "::error::the bundle is not backend/mcpp-ide.okb"; exit 1; } + for want in linux-x86_64 linux-aarch64 macos-aarch64 windows-x86_64; do + ls "$root/backend/okrun/$want/"okrun* > /dev/null 2>&1 || { echo "::error::$package carries no okrun for $want"; exit 1; } + done + okrun="$root/backend/okrun/$os-$arch/okrun$exe" + chmod +x "$okrun" 2>/dev/null || true + answers "$okrun" "$root/backend/mcpp-ide.okb" + echo "$package: one bundle; okrun for $os-$arch starts it" + exit 0 +fi + +[ -d "$root/backend" ] && { echo "::error::$package has backend/ but no bundle"; exit 1; } +echo "::notice::$package carries no ok-image bundle yet (mcpp's platforms and openkal 0.17.2); checking its per-system programs" +for want in linux-x64/mcpp-ide linux-arm64/mcpp-ide darwin-arm64/mcpp-ide win32-x64/mcpp-ide.exe; do + [ -f "$root/bin/$want" ] || { echo "::error::$package carries no bin/$want"; exit 1; } +done +program="$root/bin/$vs-$va/mcpp-ide$exe" +chmod +x "$program" 2>/dev/null || true +answers "$program" +echo "$package: a program for every system; the one for $vs-$va answers" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c0083c9..2a6fbbe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -175,3 +175,29 @@ jobs: with: name: mcpp-clion-zip path: jetbrains/build/distributions/*.zip + + # Both packages, opened on every system they serve: what each carries of the backend for that + # system starts (scripts/check-package.sh -- the ok-image bundle and its okrun once they are built). + packages: + name: packages on ${{ matrix.os }} + needs: [vscode, jetbrains] + runs-on: ${{ matrix.os }} + timeout-minutes: 15 + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04, ubuntu-24.04-arm, macos-14, windows-2022] + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v5 + - uses: actions/download-artifact@v5 + with: + pattern: mcpp-* + path: packages + merge-multiple: true + - name: The VS Code extension + run: .github/scripts/check-package.sh packages/mcpp-vscode-*.vsix extension + - name: The CLion plugin + run: .github/scripts/check-package.sh packages/mcpp-clion-*.zip mcpp-clion diff --git a/CHANGELOG.md b/CHANGELOG.md index e451079..55df7a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,3 +14,7 @@ The first release of mcpp-ide: one backend for mcpp's editor integrations, the V - VS Code: tasks, Testing view, debug configurations, Problems from mcpp, mcpp.toml editing help. - CLion: run configurations with a PTY console, test tree, CLion's debugger, console links, the mcpp tool window; depends on the mcppls CLion plugin. +- One package per editor for every system: the backend as an ok-image bundle with okrun per system + (or a program per system until the bundle is built); CI starts it from both packages on Linux + x64/arm64, macOS and Windows. +- `mcpp pack`'s package format is passed as `--pkg-format` where mcpp offers it (`--format` before). diff --git a/README.md b/README.md index 86486b9..fd429da 100644 --- a/README.md +++ b/README.md @@ -56,7 +56,10 @@ on my mcpp project. | CLion 2025.2+ | JetBrains Marketplace (`mcpp-clion`), or `mcpp-clion-<version>.zip` | Settings → Plugins → Install Plugin from Disk; the mcppls CLion plugin first | | Agents, other clients | `mcpp-ide-<version>-<platform>.tar.gz`, or `xlings install mcpp-ide` | run `mcpp-ide serve` | -Both editor packages carry the backend for Linux, macOS and Windows. +Each editor package serves every system: it carries the backend as one ok-image bundle +(`backend/mcpp-ide.okb`) and okrun for each system and architecture (mcpp's platforms, openkal +0.17.2); until that bundle is built, it carries a program for each of Linux x64/arm64, macOS arm64 +and Windows x64. ### From source diff --git a/README.zh-CN.md b/README.zh-CN.md index 9416975..8338ef5 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -51,7 +51,8 @@ C++ 文件的语言功能来自 [mcppls](https://github.com/Sunrisepeak/mcpp-lan | CLion 2025.2+ | JetBrains Marketplace(`mcpp-clion`),或 `mcpp-clion-<version>.zip` | Settings → Plugins → Install Plugin from Disk;先安装 mcppls CLion 插件 | | Agent、其他客户端 | `mcpp-ide-<version>-<platform>.tar.gz`,或 `xlings install mcpp-ide` | 运行 `mcpp-ide serve` | -两个编辑器的包都带有 Linux、macOS、Windows 的后端。 +每个编辑器包都服务全部系统:后端以一个 ok 映像包(`backend/mcpp-ide.okb`)加上各系统 × 架构的 okrun 携带 +(mcpp 的平台、openkal 0.17.2);在该映像包构建出来之前,包内携带 Linux x64/arm64、macOS arm64、Windows x64 各一份程序。 ### 从源码构建 diff --git a/docs/architecture.md b/docs/architecture.md index 5fb9bd6..18fa675 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -31,6 +31,19 @@ build through mcpp's result record, and an older or missing mcppls is reported w 5. mcpp writes the result record; the backend's watcher sends `result/changed`; mcppls reads the same record and refreshes. +## Distribution + +The backend is one program for every editor; each editor package carries it for every system: + +| Form | Layout in the package | Started as | +|---|---|---| +| ok-image bundle (mcpp design 2026-10-28 part 2 §15) | `backend/mcpp-ide.okb`, `backend/okrun/<os>-<arch>/okrun[.exe]` | `okrun mcpp-ide.okb serve`: the okrun carried for this system, else okrun on PATH | +| a program per system, until the bundle is built | `bin/<platform>/mcpp-ide[.exe]` | `mcpp-ide serve` | + +Before either, a configured `mcpp.ide.backendPath` (a program or an `.okb`) is used; after them, an +installed `mcpp-ide` (xlings, whose command runs okrun on its bundle) or one on PATH. CI opens both +packages on every system and starts what they carry for it (`.github/scripts/check-package.sh`). + ## Generated declarations `spec/` is the source of everything the editors declare statically. `mcpp-ide-dev gen vscode` writes diff --git a/jetbrains/README.md b/jetbrains/README.md index 8b8ae0b..c13321e 100644 --- a/jetbrains/README.md +++ b/jetbrains/README.md @@ -24,9 +24,11 @@ gradle buildPlugin # build/distributions/mcpp-clion-<version>.zip gradle verifyPlugin # CLion 2025.2 and the version in gradle.properties ``` -`MCPP_IDE_BACKENDS` names a directory laid out `<platform>/mcpp-ide[.exe]` (`linux-x64`, -`linux-arm64`, `darwin-arm64`, `win32-x64`) whose programs the archive carries; without it the -plugin finds the backend through `mcpp.ide.backendPath`, xlings or PATH. +What the archive carries of the backend: `MCPP_IDE_OKB` (the ok-image bundle, as +`backend/mcpp-ide.okb`) with `MCPP_IDE_OKRUN` (okrun laid out `<os>-<arch>/okrun[.exe]`), or, until +the bundle is built, `MCPP_IDE_BACKENDS` (a program per system laid out `<platform>/mcpp-ide[.exe]`: +`linux-x64`, `linux-arm64`, `darwin-arm64`, `win32-x64`). Without them the plugin finds the backend +through `mcpp.ide.backendPath`, xlings or PATH. ## Tests diff --git a/jetbrains/build.gradle.kts b/jetbrains/build.gradle.kts index e05e725..67c55e9 100644 --- a/jetbrains/build.gradle.kts +++ b/jetbrains/build.gradle.kts @@ -88,12 +88,18 @@ sourceSets { } tasks.processResources { dependsOn(generateDeclarations, copyWebui) } -// The backend programs the plugin carries, one per system (`bin/<platform>/mcpp-ide[.exe]`), from -// MCPP_IDE_BACKENDS (a directory laid out that way). Without it the plugin finds the backend on PATH -// or through xlings. +// What the plugin carries of the backend (mcpp design 2026-10-28 part 2 §15), as the VS Code +// extension carries it: MCPP_IDE_OKB, the ok-image bundle (backend/mcpp-ide.okb, one for every +// system); MCPP_IDE_OKRUN, okrun per system and architecture (backend/okrun/<os>-<arch>/); and, +// until the bundle is built, MCPP_IDE_BACKENDS, a program per system (bin/<platform>/). +val okb = providers.environmentVariable("MCPP_IDE_OKB") +val okrun = providers.environmentVariable("MCPP_IDE_OKRUN") val backends = providers.environmentVariable("MCPP_IDE_BACKENDS") tasks.prepareSandbox { - if (backends.isPresent) from(backends.get()) { into("${intellijPlatform.projectName.get()}/bin") } + val plugin = intellijPlatform.projectName.get() + if (okb.isPresent) from(okb.get()) { into("$plugin/backend"); rename { "mcpp-ide.okb" } } + if (okrun.isPresent) from(okrun.get()) { into("$plugin/backend/okrun") } + if (backends.isPresent) from(backends.get()) { into("$plugin/bin") } } intellijPlatform { diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppSession.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppSession.kt index e65e263..03dab98 100644 --- a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppSession.kt +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/McppSession.kt @@ -80,8 +80,8 @@ class McppSession(private val project: Project) : Disposable { future.completeExceptionally(IllegalStateException("mcpp-ide was not found")) return future } - log.info("mcpp-ide: starting ${located.program} (${located.source})") - val b = Backend(listOf(located.program.path, "serve")) { line -> log.info("[backend] $line") } + log.info("mcpp-ide: starting ${located.command.joinToString(" ")} (${located.source})") + val b = Backend(located.command + "serve") { line -> log.info("[backend] $line") } backend = b b.on("*") { method, params -> listeners.filter { it.first == method || it.first == "*" }.forEach { (m, fn) -> runCatching { fn(if (m == "*") JsonObject().apply { addProperty("method", method); add("params", params) } else params) } diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt index 34923d6..c5e865d 100644 --- a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt @@ -1,5 +1,12 @@ -// Where the backend is: the configured path, the one the plugin carries for this system -// (`bin/<platform>/mcpp-ide[.exe]`), the one xlings installed, then PATH. +// Where the backend is, as the command that starts it (mcpp design 2026-10-28 part 2 §15), in the +// same order as the VS Code extension: +// +// 1. mcpp.ide.backendPath: a program, or an ok-image bundle (`*.okb`) run by okrun; +// 2. the bundle the plugin carries, `backend/mcpp-ide.okb`, run by the okrun it carries for this +// system (`backend/okrun/<os>-<arch>/okrun[.exe]`), else by okrun on PATH; +// 3. a program the plugin carries for this system (`bin/<platform>/mcpp-ide[.exe]`), the form +// packages take until the bundle is built; +// 4. the mcpp-ide xlings installed, then PATH. package io.github.mcppcommunity.mcppclion.backend import java.io.File @@ -7,44 +14,67 @@ import java.io.File object Locate { val windows: Boolean = System.getProperty("os.name").lowercase().startsWith("windows") - /** "linux-x64", "darwin-arm64", "win32-x64": the same directory names the VS Code extension uses. */ - fun platformDir(os: String = System.getProperty("os.name"), arch: String = System.getProperty("os.arch")): String { + private fun system(os: String): String { val o = os.lowercase() - val system = when { - o.startsWith("windows") -> "win32" - o.startsWith("mac") || o.contains("darwin") -> "darwin" + return when { + o.startsWith("windows") -> "windows" + o.startsWith("mac") || o.contains("darwin") -> "macos" else -> "linux" } - val machine = when (arch.lowercase()) { - "amd64", "x86_64" -> "x64" - "aarch64", "arm64" -> "arm64" - else -> arch.lowercase() - } - return "$system-$machine" } - private fun exe(name: String) = if (windows) "$name.exe" else name + private fun machine(arch: String): String = when (arch.lowercase()) { + "amd64", "x86_64", "x64" -> "x86_64" + "aarch64", "arm64" -> "aarch64" + else -> arch.lowercase() + } + + /** "linux-x64", "darwin-arm64", "win32-x64": the bin/ directories, named as the VS Code extension names them. */ + fun platformDir(os: String = System.getProperty("os.name"), arch: String = System.getProperty("os.arch")): String { + val s = when (system(os)) { "windows" -> "win32"; "macos" -> "darwin"; else -> "linux" } + val m = when (machine(arch)) { "x86_64" -> "x64"; "aarch64" -> "arm64"; else -> machine(arch) } + return "$s-$m" + } + + /** "linux-x86_64", "macos-aarch64", "windows-x86_64": mcpp's names, which the okrun directories use. */ + fun okrunDir(os: String = System.getProperty("os.name"), arch: String = System.getProperty("os.arch")): String = + "${system(os)}-${machine(arch)}" + + private fun exe(name: String, onWindows: Boolean = windows) = if (onWindows) "$name.exe" else name fun onPath(name: String, path: String? = System.getenv("PATH")): File? = (path ?: "").split(File.pathSeparatorChar).filter { it.isNotEmpty() } .map { File(it, exe(name)) }.firstOrNull { it.isFile && it.canExecute() } - data class Located(val program: File, val source: String) + data class Located(val command: List<String>, val source: String) + + private fun runnable(f: File): File { + if (!windows && !f.canExecute()) f.setExecutable(true) + return f + } + + fun backend(configured: String, pluginRoot: File?, path: String? = System.getenv("PATH"), + os: String = System.getProperty("os.name"), arch: String = System.getProperty("os.arch"), + home: String = System.getProperty("user.home")): Located? { + val onWin = system(os) == "windows" + val bundledOkrun = pluginRoot?.let { File(it, "backend/okrun/${okrunDir(os, arch)}/${exe("okrun", onWin)}") } + fun okrun(): File? = bundledOkrun?.takeIf { it.isFile }?.let(::runnable) ?: onPath("okrun", path) - fun backend(configured: String, pluginRoot: File?): Located? { - if (configured.isNotBlank()) return Located(File(configured.trim()), "setting") + val c = configured.trim() + if (c.isNotEmpty()) { + if (c.endsWith(".okb")) return okrun()?.let { Located(listOf(it.path, c), "setting") } + return Located(listOf(c), "setting") + } pluginRoot?.let { root -> - val bundled = File(root, "bin/${platformDir()}/${exe("mcpp-ide")}") - if (bundled.isFile) { - if (!bundled.canExecute()) bundled.setExecutable(true) - return Located(bundled, "bundled") - } + val bundle = File(root, "backend/mcpp-ide.okb") + if (bundle.isFile) okrun()?.let { return Located(listOf(it.path, bundle.path), "bundle") } + val bundled = File(root, "bin/${platformDir(os, arch)}/${exe("mcpp-ide", onWin)}") + if (bundled.isFile) return Located(listOf(runnable(bundled).path), "bundled") } - val home = System.getProperty("user.home") - listOfNotNull(System.getenv("XLINGS_HOME")?.let { File(it, "subos/current/bin/${exe("mcpp-ide")}") }, - File(home, ".xlings/subos/current/bin/${exe("mcpp-ide")}"), - File(home, ".xlings/subos/default/bin/${exe("mcpp-ide")}")) - .firstOrNull { it.isFile }?.let { return Located(it, "xlings") } - return onPath("mcpp-ide")?.let { Located(it, "PATH") } + listOfNotNull(System.getenv("XLINGS_HOME")?.let { File(it, "subos/current/bin/${exe("mcpp-ide", onWin)}") }, + File(home, ".xlings/subos/current/bin/${exe("mcpp-ide", onWin)}"), + File(home, ".xlings/subos/default/bin/${exe("mcpp-ide", onWin)}")) + .firstOrNull { it.isFile }?.let { return Located(listOf(it.path), "xlings") } + return onPath("mcpp-ide", path)?.let { Located(listOf(it.path), "PATH") } } } diff --git a/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt b/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt index 29fefff..5d1acdd 100644 --- a/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt +++ b/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt @@ -38,6 +38,25 @@ class BackendTest { assertEquals("win32-x64", Locate.platformDir("Windows 11", "x86_64")) } + @Test + fun theBundleRunsUnderTheOkrunCarriedForThisSystem() { + assertEquals("windows-x86_64", Locate.okrunDir("Windows 11", "amd64")) + assertEquals("macos-aarch64", Locate.okrunDir("Mac OS X", "aarch64")) + val root = Files.createTempDirectory("mcppclion-okb-").toFile() + File(root, "backend/okrun/linux-x86_64").mkdirs() + File(root, "backend/mcpp-ide.okb").writeText("") + File(root, "backend/okrun/linux-x86_64/okrun").writeText("") + File(root, "bin/linux-x64").mkdirs() + File(root, "bin/linux-x64/mcpp-ide").writeText("") + val linux = Locate.backend("", root, path = "", os = "Linux", arch = "amd64", home = "/nonexistent")!! + assertEquals(listOf(File(root, "backend/okrun/linux-x86_64/okrun").path, File(root, "backend/mcpp-ide.okb").path), linux.command) + assertEquals("bundle", linux.source) + // No okrun for this system and none on PATH: the system's own program, when the package carries one. + val arm = Locate.backend("", root, path = "", os = "Linux", arch = "aarch64", home = "/nonexistent") + assertEquals(null, arm) + root.deleteRecursively() + } + @Test fun sessionOverTheMockMcpp() { val backend = System.getProperty("mcppide.backend") diff --git a/protocol/fixtures/pack-help.txt b/protocol/fixtures/pack-help.txt new file mode 100644 index 0000000..c4e56af --- /dev/null +++ b/protocol/fixtures/pack-help.txt @@ -0,0 +1,25 @@ + +Build + package: a program becomes a self-contained bundle, a library an interface + prebuilt binaries + +USAGE: + mcpp pack [OPTIONS] + mcpp pack <target> + +OPTIONS: + --mode system | vendored (default) | self-contained | static + --target Triple, e.g. x86_64-linux-musl (repeatable: one leg per triple) + --format tar (default; .zip for a Windows target) | dir | any format the resolved graph provides (e.g. appimage, msi) + -o, --output Override output path; with several members, the directory each archive or tree is written below + --profile Build profile (default: [build] default-profile, else release) + --release Shorthand for --profile release + --dev Shorthand for --profile dev + --toolchain <SPEC> Build with this toolchain for one invocation, e.g. llvm@22.1.8 + --sysroot <SYSROOT> The target's base for this invocation (= MCPP_SYSROOT): a package, glibc@system, path:<dir>, none + --features <LIST> Activate root-package features, and a dependency's as <dependency>/<feature>, for every build pass of the pack (comma-separated) + --list-formats Print the formats --format accepts here, the engine's and those the resolved graph provides, as the mcpp.pack.formats envelope + --message-format <FMT> Output format: human (default) | json (one mcpp.pack envelope on stdout; narration on stderr) + --no-strip Ship the artifacts as built (default: strip debug info) + -p, --package <NAME> Pack the named workspace member (namespace.name or package name, then directory), as if run in its directory; repeat to pack several, planned and built once + --workspace Pack every workspace member that has a program target, planned and built once + --exclude <NAME> With --workspace, leave the named member out; repeatable, refused with -p + --debug-symbols <DIR> Write the separated *.debug files here (default: discard) diff --git a/protocol/protocol.schema.json b/protocol/protocol.schema.json index 1bd2d65..d8c2331 100644 --- a/protocol/protocol.schema.json +++ b/protocol/protocol.schema.json @@ -138,8 +138,9 @@ "target": { "type": "string", "description": "The target triple; absent: the mcpp.build.target setting; empty: this machine." }, "profile": { "enum": ["dev", "release"] }, "filter": { "type": "string" }, - "format": { "type": "string" }, + "pkgFormat": { "type": "string", "description": "The package format (mcpp pack --pkg-format; --format before mcpp's platforms release)." }, "mode": { "type": "string" }, + "linkage": { "enum": ["static", "shared"] }, "spec": { "type": "string" }, "dependency": { "type": "string" }, "args": { "type": "array", "items": { "type": "string" } }, @@ -245,10 +246,14 @@ }, "graph/packages": { "params": { "$ref": "#/$defs/rooted" }, "result": { "$ref": "#/$defs/graph" } }, "graph/modules": { "params": { "$ref": "#/$defs/rooted" }, "result": { "$ref": "#/$defs/graph" } }, - "pack/formats": { "params": { "type": "object" }, "result": { "type": ["object", "null"] } }, + "pack/formats": { + "description": "The package formats mcpp offers here (mcpp pack --list-formats), the closures it packs and the linkages it takes apart from them.", + "params": { "type": "object" }, + "result": { "type": "object", "required": ["modes", "linkages"], "properties": { "formats": { "type": "array" }, "modes": { "type": "array", "items": { "type": "string" } }, "linkages": { "type": "array", "items": { "type": "string" } } } } + }, "pack/start": { "description": "A pack job (`mcpp pack --message-format json`): its envelope arrives in job/finished.", - "params": { "type": "object", "required": ["root"], "properties": { "root": { "type": "string" }, "format": { "type": "string" }, "mode": { "type": "string" }, "target": { "type": "string" }, "profile": { "type": "string" } } }, + "params": { "type": "object", "required": ["root"], "properties": { "root": { "type": "string" }, "pkgFormat": { "type": "string" }, "mode": { "type": "string" }, "linkage": { "enum": ["static", "shared"] }, "target": { "type": "string" }, "profile": { "type": "string" } } }, "result": { "$ref": "#/$defs/jobRef" } }, "manifest/check": { diff --git a/spec/i18n/runtime.zh-cn.json b/spec/i18n/runtime.zh-cn.json index ea11c8b..cc894f7 100644 --- a/spec/i18n/runtime.zh-cn.json +++ b/spec/i18n/runtime.zh-cn.json @@ -270,6 +270,7 @@ "Library root-module convention": "库根模块约定", "Licences": "许可证", "License": "许可", + "Linkage": "链接方式", "List the shared build cache": "列出共享构建缓存", "Loading…": "加载中…", "Locate focus": "定位焦点", diff --git a/src/bin/dev.cpp b/src/bin/dev.cpp index 05d4d9c..e57f067 100644 --- a/src/bin/dev.cpp +++ b/src/bin/dev.cpp @@ -5,11 +5,11 @@ // The golden fixtures under protocol/fixtures, from a real mcpp: the envelopes, streams and // records the backend reads. The mock mcpp and both adapters' tests replay them, so a change in // mcpp's contract shows up as a diff here first. -// mcpp-ide-dev gen vscode --out DIR [--stage] [--backends DIR] +// mcpp-ide-dev gen vscode --out DIR [--stage] [--okb FILE] [--okrun DIR] [--backends DIR] // The VS Code extension's declarations from spec/: package.json (vscode/package.json with the // generated commands, keybindings, menus and configuration), package.nls.json and // package.nls.zh-cn.json. With --stage, also the files the extension ships (vscode/out, media, -// syntaxes, the webui, README, CHANGELOG, LICENSE, and bin/<platform>/ from --backends): the +// syntaxes, the webui, README, CHANGELOG, LICENSE, and the backend: see stage_backend): the // directory `vsce package` packs. // mcpp-ide-dev gen jetbrains --out DIR // The CLion plugin's declarations from spec/: META-INF/mcpp-actions.xml (included by @@ -129,6 +129,10 @@ int capture(std::span<const std::string> args) { save("build-database.json", run(mcpp, {"emit", "build-database", "--format", "json"}, app).out); save("index-list.json", run(mcpp, {"index", "list", "--format", "json"}, app).out); save("pack-formats.json", run(mcpp, {"pack", "--list-formats"}, app).out); + { + auto help = run(mcpp, {"pack", "--help"}, app); + save("pack-help.txt", help.out + help.err); + } save("self-env.json", run(mcpp, {"self", "env", "--format", "json"}, app).out); // A developer's home holds hundreds of cache entries and the index hundreds of packages; the @@ -263,6 +267,27 @@ void copy_tree(const fs::path& from, const fs::path& to, std::span<const std::st } } +// What an editor package carries of the backend (mcpp design 2026-10-28 part 2 §15): +// --okb FILE (MCPP_IDE_OKB) the ok-image bundle, as backend/mcpp-ide.okb: one for every system +// --okrun DIR (MCPP_IDE_OKRUN) okrun for each system and architecture, laid out +// <os>-<arch>/okrun[.exe], as backend/okrun/ +// --backends DIR (MCPP_IDE_BACKENDS) +// programs laid out <platform>/mcpp-ide[.exe], as bin/: the form +// packages take until the bundle is built +void stage_backend(std::span<const std::string> args, const fs::path& out) { + auto from = [&](std::string_view flag, const char* variable) { + auto v = option(args, flag); + if (!v) v = mcpplibs::os::env::get(variable); + return v && !v->empty() ? std::optional<fs::path>(*v) : std::nullopt; + }; + if (auto okb = from("--okb", "MCPP_IDE_OKB")) { + fs::create_directories(out / "backend"); + fs::copy_file(*okb, out / "backend" / "mcpp-ide.okb", fs::copy_options::overwrite_existing); + } + if (auto okrun = from("--okrun", "MCPP_IDE_OKRUN")) copy_tree(*okrun, out / "backend" / "okrun"); + if (auto backends = from("--backends", "MCPP_IDE_BACKENDS")) copy_tree(*backends, out / "bin"); +} + int gen_vscode(std::span<const std::string> args) { const auto root = repo(); const auto out = fs::path(option(args, "--out").value_or((root / "vscode" / "dist" / "extension").string())); @@ -289,10 +314,7 @@ int gen_vscode(std::span<const std::string> args) { // The runtime strings, for what the extension says before its backend runs. fs::create_directories(out / "i18n"); fs::copy_file(root / "spec" / "i18n" / "runtime.zh-cn.json", out / "i18n" / "runtime.zh-cn.json", fs::copy_options::overwrite_existing); - // The backend programs, laid out bin/<platform>/mcpp-ide[.exe]: --backends, else MCPP_IDE_BACKENDS. - auto backends = option(args, "--backends"); - if (!backends) backends = mcpplibs::os::env::get("MCPP_IDE_BACKENDS"); - if (backends && !backends->empty()) copy_tree(*backends, out / "bin"); + stage_backend(args, out); } std::println("vscode declarations in {}", out.generic_string()); return 0; diff --git a/src/bin/mockmcpp.cpp b/src/bin/mockmcpp.cpp index b3b1c42..e3ab4ad 100644 --- a/src/bin/mockmcpp.cpp +++ b/src/bin/mockmcpp.cpp @@ -135,6 +135,7 @@ int main(int argc, char** argv) { if (first(0) == "run" && has("--print-launch")) { out(fixture("launch.json")); return 0; } if (first(0) == "search") { out(fixture("search.json")); return 0; } if (first(0) == "index" && first(1) == "list") { out(fixture("index-list.json")); return 0; } + if (first(0) == "pack" && has("--help")) { out(fixture("pack-help.txt")); return 0; } if (first(0) == "pack" && has("--list-formats")) { out(fixture("pack-formats.json")); return 0; } if (first(0) == "toolchain" && first(1) == "list") { out(fixture("toolchain-list.json")); return 0; } if (first(0) == "cache" && first(1) == "list") { out(fixture("cache-list.json")); return 0; } diff --git a/src/mcpp.cppm b/src/mcpp.cppm index b8c5df9..08dccff 100644 --- a/src/mcpp.cppm +++ b/src/mcpp.cppm @@ -72,6 +72,7 @@ public: int exitCode = -1; Json envelope; // null when standard output held no JSON std::string narration; // standard error + std::string output; // standard output as it was printed }; std::expected<EnvelopeResult, std::string> envelope(const RunOptions& o) const; @@ -220,6 +221,7 @@ std::expected<Client::EnvelopeResult, std::string> Client::envelope(const RunOpt EnvelopeResult out; out.exitCode = r->status.shell_code(); out.narration = std::move(r->err); + out.output = r->out; // One document, or NDJSON whose last line is the envelope. auto doc = Json::parse(r->out, nullptr, false); if (doc.is_discarded()) { diff --git a/src/server.cppm b/src/server.cppm index 7dfd531..7230cc1 100644 --- a/src/server.cppm +++ b/src/server.cppm @@ -117,6 +117,15 @@ private: std::map<std::string, std::pair<std::filesystem::path, std::string>, std::less<>> jobOf_; // The configuration (and platforms) the last plan of each project named. std::map<std::filesystem::path, Json> plans_; + // What `mcpp pack` accepts, read from its help once per mcpp (SPEC-014: `--pkg-format` names the + // package format since the platforms release; an earlier mcpp knows it as `--format`). + struct PackOptions { + std::filesystem::path program; + std::string pkgFormatFlag = "--format"; + bool linkage = false; + }; + std::optional<PackOptions> packOptions_; + PackOptions pack_options(const std::filesystem::path& cwd); }; } // namespace mcppide::server @@ -494,9 +503,11 @@ std::expected<Json, rpc::Error> Session::job_start(const Json& p) { r.mode = jobs::Mode::ndjson; break; case jobs::Kind::pack: { + const auto options = pack_options(root); r.args = {"pack"}; - if (p.contains("format") && p["format"].is_string()) { r.args.push_back("--format"); r.args.push_back(p["format"]); } - if (p.contains("mode") && p["mode"].is_string()) { r.args.push_back("--mode"); r.args.push_back(p["mode"]); } + if (auto f = p.value("pkgFormat", ""); !f.empty()) { r.args.push_back(options.pkgFormatFlag); r.args.push_back(f); } + if (auto m = p.value("mode", ""); !m.empty()) { r.args.push_back("--mode"); r.args.push_back(m); } + if (auto l = p.value("linkage", ""); !l.empty() && options.linkage) { r.args.push_back("--linkage"); r.args.push_back(l); } if (release) r.args.push_back("--release"); append(target); r.args.push_back("--message-format"); @@ -905,6 +916,25 @@ std::expected<Json, rpc::Error> Session::test_list(const Json& p) { return Json{{"root", root.generic_string()}, {"tests", tests}}; } +Session::PackOptions Session::pack_options(const std::filesystem::path& cwd) { + mcpp::Client client; + { + std::lock_guard lock(mutex_); + client = client_; + if (packOptions_ && packOptions_->program == client.program()) return *packOptions_; + } + PackOptions o; + o.program = client.program(); + if (auto r = query(cwd, {"pack", "--help"})) { + const auto help = r->output + r->narration; + if (help.find("--pkg-format") != std::string::npos) o.pkgFormatFlag = "--pkg-format"; + o.linkage = help.find("--linkage") != std::string::npos; + } + std::lock_guard lock(mutex_); + packOptions_ = o; + return o; +} + void Session::install() { auto& s = rpc_; s.on("initialize", [this](const Json& p, const rpc::Context&) { return initialize(p); }); @@ -1015,7 +1045,13 @@ void Session::install() { s.on("pack/formats", [this](const Json& p, const rpc::Context&) -> Result { auto r = query(any_root(p), {"pack", "--list-formats"}); if (!r) return std::unexpected(r.error()); - return r->envelope.is_object() ? r->envelope["data"] : Json(nullptr); + Json out = r->envelope.is_object() && r->envelope.contains("data") ? r->envelope["data"] : Json::object(); + const auto options = pack_options(any_root(p)); + // The closures every mcpp since 2026.10.26.1 packs (SPEC-014), and the linkages where it + // takes them apart from the closure. + out["modes"] = Json::array({"vendored", "system", "self-contained", "static"}); + out["linkages"] = options.linkage ? Json::array({"static", "shared"}) : Json::array(); + return out; }); s.on("pack/start", [this](const Json& p, const rpc::Context&) -> Result { Json job = p; diff --git a/tests/test_protocol.cpp b/tests/test_protocol.cpp index 87eb988..8c8c07e 100644 --- a/tests/test_protocol.cpp +++ b/tests/test_protocol.cpp @@ -128,6 +128,11 @@ int main() { for (const auto& c : cmds["commands"]) CHECK(c["action"]["kind"] != "forward"); result_of("menu/quick", rooted); result_of("languageService/status", Json{{"candidates", Json::array()}}); + // The pack panel's choices: the closures SPEC-014 names, and linkages only where mcpp takes them. + auto pack = result_of("pack/formats", rooted); + CHECK(pack["modes"].size() == 4); + const bool helpNamesLinkage = testsupport::read(testsupport::fixtures() / "pack-help.txt").find("--linkage") != std::string::npos; + CHECK(pack["linkages"].empty() != helpNamesLinkage); result_of("graph/packages", rooted); result_of("graph/modules", rooted); result_of("manifest/check", rooted); diff --git a/vscode/README.md b/vscode/README.md index b56ff20..eebb51f 100644 --- a/vscode/README.md +++ b/vscode/README.md @@ -37,8 +37,9 @@ every build, whoever runs it; the project view says when the installed mcppls is ## Requirements - mcpp 2026.10.26.1 or later (`xlings install mcpp`). -- The mcpp-ide backend: shipped inside the extension for Linux, macOS and Windows; otherwise - `xlings install mcpp-ide`, or set `mcpp.ide.backendPath`. +- The mcpp-ide backend: shipped inside the extension for every system (one ok-image bundle run by + okrun, or a program per system); otherwise `xlings install mcpp-ide`, or set + `mcpp.ide.backendPath` (a program or an `.okb`). ## Upgrading from 0.9 diff --git a/vscode/src/backend/locate.ts b/vscode/src/backend/locate.ts index 8724f20..6543672 100644 --- a/vscode/src/backend/locate.ts +++ b/vscode/src/backend/locate.ts @@ -1,12 +1,21 @@ -// Where the backend is: the configured path, the one the extension carries for this system -// (`bin/<platform>/mcpp-ide[.exe]`), the one xlings installed, then PATH. +// Where the backend is, as the command that starts it (mcpp design 2026-10-28 part 2 §15): +// +// 1. mcpp.ide.backendPath: a program, or an ok-image bundle (`*.okb`) run by okrun; +// 2. the bundle the extension carries, `backend/mcpp-ide.okb`, run by the okrun it carries for +// this system (`backend/okrun/<os>-<arch>/okrun[.exe]`), else by okrun on PATH -- one package +// for every system and architecture; +// 3. a program the extension carries for this system (`bin/<platform>/mcpp-ide[.exe]`), the form +// packages take until the bundle is built; +// 4. the mcpp-ide xlings installed (its command runs okrun on its bundle), then PATH. import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; export interface Located { program: string; - source: "setting" | "bundled" | "xlings" | "PATH"; + /** Arguments before the backend's own (`serve`): the bundle, when okrun runs one. */ + args: string[]; + source: "setting" | "bundle" | "bundled" | "xlings" | "PATH"; } /** "linux-x64", "darwin-arm64", "win32-x64": the directory under bin/ for this system. */ @@ -14,6 +23,13 @@ export function platformDir(platform: NodeJS.Platform = process.platform, arch: return `${platform}-${arch}`; } +/** mcpp's names for a system and an architecture: "linux-x86_64", "macos-aarch64", "windows-x86_64". */ +export function okrunDir(platform: NodeJS.Platform = process.platform, arch: string = process.arch): string { + const system = platform === "win32" ? "windows" : platform === "darwin" ? "macos" : platform; + const machine = arch === "x64" ? "x86_64" : arch === "arm64" ? "aarch64" : arch; + return `${system}-${machine}`; +} + function executable(name: string, platform: NodeJS.Platform): string { return platform === "win32" ? `${name}.exe` : name; } @@ -26,6 +42,14 @@ function isFile(p: string): boolean { } } +// A package's archive need not keep the mode bits. +function runnable(p: string, platform: NodeJS.Platform): string { + if (platform !== "win32") { + try { fs.accessSync(p, fs.constants.X_OK); } catch { try { fs.chmodSync(p, 0o755); } catch { /* reported when it is started */ } } + } + return p; +} + export function onPath(name: string, env: NodeJS.ProcessEnv = process.env, platform: NodeJS.Platform = process.platform): string | undefined { const dirs = (env.PATH ?? env.Path ?? "").split(platform === "win32" ? ";" : ":").filter(Boolean); for (const d of dirs) { @@ -44,28 +68,35 @@ export function locateBackend(options: { home?: string; }): Located | undefined { const platform = options.platform ?? process.platform; + const arch = options.arch ?? process.arch; const env = options.env ?? process.env; - const exe = executable("mcpp-ide", platform); - if (options.configured && options.configured.trim()) { - return { program: options.configured.trim(), source: "setting" }; - } - const bundled = path.join(options.extensionRoot, "bin", platformDir(platform, options.arch ?? process.arch), exe); - if (isFile(bundled)) { - // A package's archive need not keep the mode bits. - if (platform !== "win32") { - try { fs.accessSync(bundled, fs.constants.X_OK); } catch { try { fs.chmodSync(bundled, 0o755); } catch { /* reported when it is started */ } } + const bundledOkrun = path.join(options.extensionRoot, "backend", "okrun", okrunDir(platform, arch), executable("okrun", platform)); + const okrun = (): string | undefined => (isFile(bundledOkrun) ? runnable(bundledOkrun, platform) : onPath("okrun", env, platform)); + + const configured = options.configured?.trim(); + if (configured) { + if (configured.endsWith(".okb")) { + const runner = okrun(); + return runner ? { program: runner, args: [configured], source: "setting" } : undefined; } - return { program: bundled, source: "bundled" }; + return { program: configured, args: [], source: "setting" }; } + const bundle = path.join(options.extensionRoot, "backend", "mcpp-ide.okb"); + if (isFile(bundle)) { + const runner = okrun(); + if (runner) return { program: runner, args: [bundle], source: "bundle" }; + } + const bundled = path.join(options.extensionRoot, "bin", platformDir(platform, arch), executable("mcpp-ide", platform)); + if (isFile(bundled)) return { program: runnable(bundled, platform), args: [], source: "bundled" }; + const exe = executable("mcpp-ide", platform); const home = options.home ?? os.homedir(); - const xlingsHome = env.XLINGS_HOME; for (const candidate of [ - xlingsHome ? path.join(xlingsHome, "subos", "current", "bin", exe) : undefined, + env.XLINGS_HOME ? path.join(env.XLINGS_HOME, "subos", "current", "bin", exe) : undefined, path.join(home, ".xlings", "subos", "current", "bin", exe), path.join(home, ".xlings", "subos", "default", "bin", exe), ]) { - if (candidate && isFile(candidate)) return { program: candidate, source: "xlings" }; + if (candidate && isFile(candidate)) return { program: candidate, args: [], source: "xlings" }; } const found = onPath("mcpp-ide", env, platform); - return found ? { program: found, source: "PATH" } : undefined; + return found ? { program: found, args: [], source: "PATH" } : undefined; } diff --git a/vscode/src/session.ts b/vscode/src/session.ts index ba3d9ae..6d8b17a 100644 --- a/vscode/src/session.ts +++ b/vscode/src/session.ts @@ -100,9 +100,10 @@ export class Session implements vscode.Disposable { }); return false; } - this.output.appendLine(`mcpp-ide: starting ${this.located.program} (${this.located.source})`); + this.output.appendLine(`mcpp-ide: starting ${[this.located.program, ...this.located.args].join(" ")} (${this.located.source})`); const backend = new Backend({ program: this.located.program, + args: [...this.located.args, "serve"], log: (line) => this.output.appendLine(`[backend] ${line}`), }); this.backend = backend; diff --git a/vscode/test/unit/locate.test.ts b/vscode/test/unit/locate.test.ts index 7bc92aa..70a4826 100644 --- a/vscode/test/unit/locate.test.ts +++ b/vscode/test/unit/locate.test.ts @@ -5,12 +5,12 @@ import * as os from "node:os"; import * as path from "node:path"; import { test } from "node:test"; -import { locateBackend, onPath, platformDir } from "../../src/backend/locate"; +import { locateBackend, okrunDir, onPath, platformDir } from "../../src/backend/locate"; import { mcpplsCandidates } from "../../src/backend/mcppls"; test("the configured path wins, then the bundled program", () => { const ext = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-ext-")); - assert.deepEqual(locateBackend({ configured: "/x/mcpp-ide", extensionRoot: ext }), { program: "/x/mcpp-ide", source: "setting" }); + assert.deepEqual(locateBackend({ configured: "/x/mcpp-ide", extensionRoot: ext }), { program: "/x/mcpp-ide", args: [], source: "setting" }); const dir = path.join(ext, "bin", platformDir("linux", "x64")); fs.mkdirSync(dir, { recursive: true }); fs.writeFileSync(path.join(dir, "mcpp-ide"), ""); @@ -19,6 +19,28 @@ test("the configured path wins, then the bundled program", () => { assert.equal(platformDir("win32", "x64"), "win32-x64"); }); +test("the bundle runs under the okrun carried for this system, else okrun on PATH, before a native program", () => { + const ext = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-okb-")); + fs.mkdirSync(path.join(ext, "backend", "okrun", "linux-x86_64"), { recursive: true }); + fs.writeFileSync(path.join(ext, "backend", "mcpp-ide.okb"), ""); + fs.writeFileSync(path.join(ext, "backend", "okrun", "linux-x86_64", "okrun"), ""); + fs.mkdirSync(path.join(ext, "bin", "linux-x64"), { recursive: true }); + fs.writeFileSync(path.join(ext, "bin", "linux-x64", "mcpp-ide"), ""); + const linux = locateBackend({ extensionRoot: ext, platform: "linux", arch: "x64", env: { PATH: "" }, home: "/nonexistent" }); + assert.deepEqual(linux, { program: path.join(ext, "backend", "okrun", "linux-x86_64", "okrun"), args: [path.join(ext, "backend", "mcpp-ide.okb")], source: "bundle" }); + // No okrun carried for macOS: okrun on PATH runs the bundle. + const bin = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-okrun-")); + fs.writeFileSync(path.join(bin, "okrun"), ""); + const mac = locateBackend({ extensionRoot: ext, platform: "darwin", arch: "arm64", env: { PATH: bin }, home: "/nonexistent" }); + assert.deepEqual(mac?.args, [path.join(ext, "backend", "mcpp-ide.okb")]); + assert.equal(mac?.program, path.join(bin, "okrun")); + // No okrun at all: the native program for the system, if the package carries one. + const native = locateBackend({ extensionRoot: ext, platform: "linux", arch: "arm64", env: { PATH: "" }, home: "/nonexistent" }); + assert.equal(native, undefined); + assert.equal(okrunDir("win32", "x64"), "windows-x86_64"); + assert.equal(okrunDir("darwin", "arm64"), "macos-aarch64"); +}); + test("PATH lookup appends .exe on Windows", () => { const dir = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-path-")); fs.writeFileSync(path.join(dir, "mcpp-ide.exe"), ""); diff --git a/webui/js/panels/pack.js b/webui/js/panels/pack.js index dc8b007..8f20c6e 100644 --- a/webui/js/panels/pack.js +++ b/webui/js/panels/pack.js @@ -11,8 +11,8 @@ mount(el, params) { const rootDir = params.root; const format = h("select"); - const mode = h("select", ["", "static", "bundle-project", "bundle-all", "self-contained"].map((m) => - h("option", { value: m }, m || t("the project's default")))); + const mode = h("select", h("option", { value: "" }, t("the project's default"))); + const linkage = h("select", h("option", { value: "" }, t("the project's default"))); const profile = h("select", ["release", "dev"].map((p) => h("option", { value: p }, p))); const target = h("input", { type: "text", placeholder: t("this machine") }); const output = h("pre.log"); @@ -21,8 +21,8 @@ const go = ui.button(t("Pack"), async () => { ui.clear(output); ui.clear(result); try { - const r = await ui.rpc("pack/start", { root: rootDir, format: format.value || undefined, mode: mode.value || undefined, - profile: profile.value, target: target.value }); + const r = await ui.rpc("pack/start", { root: rootDir, pkgFormat: format.value || undefined, mode: mode.value || undefined, + linkage: linkage.value || undefined, profile: profile.value, target: target.value }); jobId = r.jobId; go.disabled = true; } catch (e) { result.appendChild(ui.errorBox(e)); } }); @@ -47,6 +47,7 @@ h("dl.facts", h("dt", t("Format")), h("dd", format), h("dt", t("Mode")), h("dd", mode), + h("dt", t("Linkage")), h("dd", linkage), h("dt", t("Profile")), h("dd", profile), h("dt", t("Target")), h("dd", target)), h("div.actions", go)), @@ -55,6 +56,9 @@ format.appendChild(h("option", { value: "" }, t("the project's default"))); for (const f of (r && r.formats) || []) format.appendChild(h("option", { value: f.name }, f.builtin ? f.name : `${f.name} (${(f.providers || []).join(", ")})`)); + for (const m of (r && r.modes) || []) mode.appendChild(h("option", { value: m }, m)); + for (const l of (r && r.linkages) || []) linkage.appendChild(h("option", { value: l }, l)); + linkage.disabled = !((r && r.linkages) || []).length; }, (e) => result.appendChild(ui.errorBox(e))); ui.host("settings", {}).then((s) => { if (s && s["mcpp.build.target"]) target.value = s["mcpp.build.target"]; }); return () => offs.forEach((off) => off()); From 80476a5e904f6e5c90cc5c1db0d26dad4ed6e5d3 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 05:06:41 +0900 Subject: [PATCH 15/30] CI: the plugin's variables hold for every Gradle run of its job, so the verifier's rebuild keeps the backends; the archive is checked after it Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/workflows/ci.yml | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2a6fbbe..69c881e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -157,20 +157,25 @@ jobs: run: | chmod +x backends/*/mcpp-ide* mcpp build + # Every Gradle run of this job packages the same plugin: the variables hold for all of them. + bin="$(cd "$(dirname "$(ls -t target/*/*/bin/mcpp-ide | head -1)")" && pwd)" + { + echo "MCPP_IDE_DEV=$bin/mcpp-ide-dev" + echo "MCPP_IDE_BACKEND=$bin/mcpp-ide" + echo "MCPP_IDE_MOCK_MCPP=$bin/mcpp-ide-mock-mcpp" + echo "MCPP_IDE_BACKENDS=$GITHUB_WORKSPACE/backends" + } >> "$GITHUB_ENV" - name: Test and package working-directory: jetbrains - run: | - bin="$(cd "$(dirname "$(ls -t ../target/*/*/bin/mcpp-ide | head -1)")" && pwd)" - export MCPP_IDE_DEV="$bin/mcpp-ide-dev" MCPP_IDE_BACKEND="$bin/mcpp-ide" MCPP_IDE_MOCK_MCPP="$bin/mcpp-ide-mock-mcpp" - export MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" - gradle --no-daemon test buildPlugin - unzip -l build/distributions/mcpp-clion-*.zip | tee files.txt - for p in linux-x64/mcpp-ide linux-arm64/mcpp-ide darwin-arm64/mcpp-ide win32-x64/mcpp-ide.exe; do grep -q "mcpp-clion/bin/$p" files.txt; done + run: gradle --no-daemon test buildPlugin - name: Plugin Verifier + working-directory: jetbrains + run: gradle --no-daemon verifyPlugin + - name: The archive carries every system's backend working-directory: jetbrains run: | - export MCPP_IDE_DEV="$(cd "$(dirname "$(ls -t ../target/*/*/bin/mcpp-ide-dev | head -1)")" && pwd)/mcpp-ide-dev" - gradle --no-daemon verifyPlugin + unzip -l build/distributions/mcpp-clion-*.zip | tee files.txt + for p in linux-x64/mcpp-ide linux-arm64/mcpp-ide darwin-arm64/mcpp-ide win32-x64/mcpp-ide.exe; do grep -q "mcpp-clion/bin/$p" files.txt; done - uses: actions/upload-artifact@v5 with: name: mcpp-clion-zip From 6ee5aa5db849304f2c701ee042e3f6666e2cc706 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 05:27:04 +0900 Subject: [PATCH 16/30] check-package.sh: no /dev/stderr on Windows Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/scripts/check-package.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/scripts/check-package.sh b/.github/scripts/check-package.sh index bae7452..0f6abef 100755 --- a/.github/scripts/check-package.sh +++ b/.github/scripts/check-package.sh @@ -18,7 +18,10 @@ case "$(uname -m)" in x86_64|amd64|AMD64) arch=x86_64 va=x64 ;; aarch64|arm64|AR exe=""; [ "$os" = windows ] && exe=".exe" answers() { # <argv...>: the backend says who it is - "$@" --version | tee /dev/stderr | grep -q '^mcpp-ide ' + local said + said="$("$@" --version)" + echo "$said" + grep -q '^mcpp-ide ' <<< "$said" } okbs="$(find "$root" -name '*.okb' | wc -l | tr -d ' ')" From c2af36394477e28ddddf96bd108c6c7a86b88a85 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <x.xllmapi@gmail.com> Date: Wed, 28 Oct 2026 05:46:39 +0900 Subject: [PATCH 17/30] e2e: MCPP_E2E_EXTENSION runs the suite on another extension directory (an unpacked .vsix) Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- vscode/test/e2e/runTest.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/vscode/test/e2e/runTest.ts b/vscode/test/e2e/runTest.ts index d2ba515..2a6f172 100644 --- a/vscode/test/e2e/runTest.ts +++ b/vscode/test/e2e/runTest.ts @@ -28,7 +28,8 @@ async function main(): Promise<void> { "security.workspace.trust.enabled": false, })); const executable = process.env.MCPP_E2E_CODE; - const extensionDevelopmentPath = path.join(repo, "vscode", "dist", "extension"); + // MCPP_E2E_EXTENSION: another extension directory (an unpacked .vsix) in place of the staged one. + const extensionDevelopmentPath = process.env.MCPP_E2E_EXTENSION ?? path.join(repo, "vscode", "dist", "extension"); await runTests({ ...(executable ? { vscodeExecutablePath: executable } : { version: "1.91.0" }), extensionDevelopmentPath, From 285732be330fdbf604f125f4efbadb5c1af1d99c Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 09:55:42 +0900 Subject: [PATCH 18/30] Fixtures from mcpp 2026.10.27.1: a target row names its platform as a package spec, a plan states the platform and the host's in its configuration, a wrapped program's launch is resolved by --print-launch; toolchains stated per target system, so the ok-image targets take openkal-platform 0.17.2's; os by its 0.2.1 branch Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- mcpp.lock | 11 +- mcpp.toml | 23 +- protocol/fixtures/build-database.json | 18 +- protocol/fixtures/build-failed.ndjson | 4 +- protocol/fixtures/build-manifest-error.ndjson | 2 +- protocol/fixtures/build-ok.ndjson | 6 +- protocol/fixtures/build-platform.ndjson | 1893 +++++++++++++++++ protocol/fixtures/cache-list.json | 432 ++-- protocol/fixtures/index-list.json | 2 +- protocol/fixtures/launch.json | 6 +- protocol/fixtures/pack-formats.json | 2 +- protocol/fixtures/pack-help.txt | 12 +- protocol/fixtures/protocol-version.json | 2 +- protocol/fixtures/result-ok.json | 20 +- protocol/fixtures/search.json | 2 +- protocol/fixtures/self-env.json | 6 +- protocol/fixtures/test.ndjson | 4 +- .../fixtures/toolchain-list-platform.json | 314 +++ protocol/fixtures/toolchain-list.json | 32 +- protocol/fixtures/version.txt | 2 +- protocol/mcpp-contract.schema.json | 14 +- src/bin/dev.cpp | 2 +- src/views.cppm | 25 +- tests/test_views.cpp | 19 +- 24 files changed, 2566 insertions(+), 287 deletions(-) create mode 100644 protocol/fixtures/build-platform.ndjson create mode 100644 protocol/fixtures/toolchain-list-platform.json diff --git a/mcpp.lock b/mcpp.lock index 3b5460d..9f6ebe5 100644 --- a/mcpp.lock +++ b/mcpp.lock @@ -5,6 +5,11 @@ # file must not change depending on which command ran last. version = 2 +[package."os"] +version = "os-0.2.1" +source = "git+https://github.com/mcpplibs/os.git#branch=os-0.2.1@211e765edbed99ef02526c45af9da988f6e48399" +hash = "fnv1a:e9ea51f425a4832f" + [package."openkal"] namespace = "mcpplibs" version = "0.17.1" @@ -17,12 +22,6 @@ version = "0.18.2" source = "index+mcpplibs@0.18.2" hash = "fnv1a:2947b54ddbcf8813" -[package."os"] -namespace = "mcpplibs" -version = "0.2.0" -source = "index+mcpplibs@0.2.0" -hash = "fnv1a:2fbee4a8617c3781" - [package."nlohmann.json"] namespace = "nlohmann" version = "3.12.0" diff --git a/mcpp.toml b/mcpp.toml index aa0f413..446e3cb 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -14,7 +14,7 @@ description = "The IDE backend for mcpp: sessions, jobs, records and view models license = "Apache-2.0" authors = ["mcpp-community"] repo = "https://github.com/mcpp-community/mcpp-ide" -mcpp = ">=2026.10.26.1" +mcpp = ">=2026.10.27.1" [language] standard = "c++23" @@ -22,12 +22,16 @@ modules = true import_std = true # As mcpp itself builds: GCC on Linux, the xlings LLVM on macOS and Windows, each for its own -# system. The Linux programs the editor packages carry are static musl ones, cross-built for arm64 -# from x86_64 as well (the target table pins musl-gcc for both rows). -[toolchain] -default = "gcc@16.1.0" -macos = "llvm@23.1.3" -windows = "llvm@23.1.3" +# system. Stated per target system, so a target whose platform states its toolchain -- the ok +# images the editor packages carry (`<arch>-openkal`, openkal-platform's llvm) -- takes it. +[target.'cfg(linux)'] +toolchain = "gcc@16.1.0" + +[target.'cfg(macos)'] +toolchain = "llvm@23.1.3" + +[target.'cfg(windows)'] +toolchain = "llvm@23.1.3" # An arm64 Linux machine's own programs: the xlings gcc payload has no aarch64-hosted C++ frontend. [target.aarch64-linux-gnu] @@ -59,7 +63,10 @@ kind = "bin" main = "src/bin/dev.cpp" [dependencies] -os = "0.2.0" +# os 0.2.1 (mcpplibs/os#7): an ok image's C library, C++ run-time and loader are its platform's, +# so the package declares no openkal-tools of its own beside the platform's. By its branch until +# it is published. +os = { git = "https://github.com/mcpplibs/os.git", branch = "os-0.2.1" } [dependencies.nlohmann] json = "3.12.0" diff --git a/protocol/fixtures/build-database.json b/protocol/fixtures/build-database.json index 3b7b488..75919de 100644 --- a/protocol/fixtures/build-database.json +++ b/protocol/fixtures/build-database.json @@ -4,7 +4,7 @@ "ide": { "generator": { "name": "mcpp", - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "profile-version": "0.3.0", "toolchains": { @@ -60,20 +60,20 @@ "-c", "@ROOT@/src/main.cpp", "-o", - "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30/obj/main.o" + "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/main.o" ], "ide": { "role": "non-module" }, "local-arguments": [], - "object": "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30/obj/main.o", + "object": "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/main.o", "private": false, "provides": {}, "requires": [ "std" ], "source": "@ROOT@/src/main.cpp", - "work-directory": "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30" + "work-directory": "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416" } ], "visible-sets": [ @@ -114,20 +114,20 @@ "-c", "@ROOT@/tests/test_smoke.cpp", "-o", - "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30/obj/test_smoke.o" + "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/test_smoke.o" ], "ide": { "role": "non-module" }, "local-arguments": [], - "object": "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30/obj/test_smoke.o", + "object": "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/test_smoke.o", "private": false, "provides": {}, "requires": [ "std" ], "source": "@ROOT@/tests/test_smoke.cpp", - "work-directory": "@HOME@/.mcpp/cache/build-database/784dcf29dac2b1c4/target/x86_64-linux-gnu/b4dbdb186bc3ef30" + "work-directory": "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416" } ], "visible-sets": [ @@ -186,7 +186,7 @@ ], "version": 1 }, - "inputs-fingerprint": "fnv1a:3c9c1199d9bc1143", + "inputs-fingerprint": "fnv1a:dacb6fd7fa58be28", "spec": { "name": "s1", "version": "0.3.0" @@ -217,7 +217,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/build-failed.ndjson b/protocol/fixtures/build-failed.ndjson index d2ca619..6bd1a04 100644 --- a/protocol/fixtures/build-failed.ndjson +++ b/protocol/fixtures/build-failed.ndjson @@ -1,6 +1,6 @@ -{"configuration":{"fingerprint":"b4dbdb186bc3ef30","outputDir":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30","profile":"dev","triple":"x86_64-linux-gnu"},"event":"plan","kind":"mcpp.event","schemaVersion":1} +{"configuration":{"fingerprint":"77ba4e6c37abd416","hostPlatform":null,"outputDir":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416","platform":null,"profile":"dev","triple":"x86_64-linux-gnu"},"event":"plan","kind":"mcpp.event","schemaVersion":1} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":2} {"diagnostic":{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"},"event":"diagnostic","kind":"mcpp.event","schemaVersion":1} -{"data":{"artifacts":[],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/compile_commands.json","configuration":{"fingerprint":"b4dbdb186bc3ef30","outputDir":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30","profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"}],"finishedAt":1793118345609,"pid":1768262,"startedAt":1793118345588,"status":"failed"},"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"build failed in app v0.1.0 (.)","severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.2"},"schemaVersion":1} +{"data":{"artifacts":[],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/compile_commands.json","configuration":{"fingerprint":"77ba4e6c37abd416","hostPlatform":null,"outputDir":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416","platform":null,"profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"}],"finishedAt":1793148661270,"pid":1209305,"startedAt":1793148661248,"status":"failed"},"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"build failed in app v0.1.0 (.)","severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} diff --git a/protocol/fixtures/build-manifest-error.ndjson b/protocol/fixtures/build-manifest-error.ndjson index 42b0386..2f11df1 100644 --- a/protocol/fixtures/build-manifest-error.ndjson +++ b/protocol/fixtures/build-manifest-error.ndjson @@ -1 +1 @@ -{"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"@ROOT@/mcpp.toml:1:9: error: expected ']'","path":"@ROOT@/mcpp.toml","range":{"end":{"column":9,"line":1},"start":{"column":9,"line":1}},"severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.2"},"schemaVersion":1} +{"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"@ROOT@/mcpp.toml:1:9: error: expected ']'","path":"@ROOT@/mcpp.toml","range":{"end":{"column":9,"line":1},"start":{"column":9,"line":1}},"severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} diff --git a/protocol/fixtures/build-ok.ndjson b/protocol/fixtures/build-ok.ndjson index 8aafe41..c6fd72b 100644 --- a/protocol/fixtures/build-ok.ndjson +++ b/protocol/fixtures/build-ok.ndjson @@ -1,9 +1,9 @@ -{"configuration":{"fingerprint":"b4dbdb186bc3ef30","outputDir":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30","profile":"dev","triple":"x86_64-linux-gnu"},"event":"plan","kind":"mcpp.event","schemaVersion":1} +{"configuration":{"fingerprint":"77ba4e6c37abd416","hostPlatform":null,"outputDir":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416","platform":null,"profile":"dev","triple":"x86_64-linux-gnu"},"event":"plan","kind":"mcpp.event","schemaVersion":1} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":4} {"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":4} {"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":4} {"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":4} -{"artifact":{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app"},"event":"artifact","kind":"mcpp.event","schemaVersion":1} -{"data":{"artifacts":[{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app"}],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/compile_commands.json","configuration":{"fingerprint":"b4dbdb186bc3ef30","outputDir":"@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30","profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[],"finishedAt":1793118343698,"pid":1767942,"startedAt":1793118343022,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.26.2"},"schemaVersion":1} +{"artifact":{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"},"event":"artifact","kind":"mcpp.event","schemaVersion":1} +{"data":{"artifacts":[{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"}],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/compile_commands.json","configuration":{"fingerprint":"77ba4e6c37abd416","hostPlatform":null,"outputDir":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416","platform":null,"profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[],"finishedAt":1793148650353,"pid":1203929,"startedAt":1793148649554,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} diff --git a/protocol/fixtures/build-platform.ndjson b/protocol/fixtures/build-platform.ndjson new file mode 100644 index 0000000..19c41b4 --- /dev/null +++ b/protocol/fixtures/build-platform.ndjson @@ -0,0 +1,1893 @@ +{"configuration":{"fingerprint":"38fc4cae0272ddf9","hostPlatform":null,"outputDir":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9","platform":{"fields":{"carrier":{"source":"platform","value":"openkal-run@0.1.3"},"layers.c++-abi":{"source":"platform","value":"openkal-llvm-runtime@0.16.5"},"layers.c-abi":{"source":"platform","value":"openkal-musl@0.22.5"},"layers.compiler-runtime":{"source":"platform","value":"openkal-llvm-runtime@0.16.5"},"link.driver":{"source":"platform","value":"lld"},"link.exe":{"source":"platform","value":"{name}.oke"},"link.shared":{"source":"platform","value":"lib{name}.okso"},"link.start":{"source":"platform","value":"ok_main"},"runner":{"source":"platform","value":["okrun","{}"]},"toolchain":{"source":"platform","value":"llvm@23.1.3"},"tools.okld":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/0daa33111e083da8/bin/okld"},"tools.okrun":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/3e48df0058ef2949/bin/okrun"}},"hosted":false,"name":"openkal-platform","source":"built-in","version":"0.17.2"},"profile":"dev","triple":"aarch64-openkal"},"event":"plan","kind":"mcpp.event","schemaVersion":1} +{"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":5,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":6,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":7,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":8,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":9,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":10,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":11,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":12,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":13,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":14,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":15,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":16,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":17,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":18,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":19,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":20,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":21,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":22,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":23,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":24,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":25,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":26,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":27,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":28,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":29,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":30,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":31,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":32,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":33,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":34,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":35,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":36,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":37,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":38,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":39,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":40,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":41,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":42,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":43,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":44,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":45,"kind":"mcpp.event","schemaVersion":1,"total":45} +{"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":5,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":6,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":7,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":8,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":9,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":10,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":11,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":12,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":13,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":14,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":15,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":16,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":17,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":18,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":19,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":20,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":21,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":22,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":23,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":24,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":25,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":26,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":27,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":28,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":29,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":30,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":31,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":32,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":33,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":34,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":35,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":36,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":37,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":38,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":39,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":40,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":41,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":42,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":43,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":44,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":45,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":46,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":47,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":48,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":49,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":50,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":51,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":52,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":53,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":54,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":55,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":56,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":57,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":58,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":59,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":60,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":61,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":62,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":63,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":64,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":65,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":66,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":67,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":68,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":69,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":70,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":71,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":72,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":73,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":74,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":75,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":76,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":77,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":78,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":79,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":80,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":81,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":82,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":83,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":84,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":85,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":86,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":87,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":88,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":89,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":90,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":91,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":92,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":93,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":94,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":95,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":96,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":97,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":98,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":99,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":100,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":101,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":102,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":103,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":104,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":105,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":106,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":107,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":108,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":109,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":110,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":111,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":112,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":113,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":114,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":115,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":116,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":117,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":118,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":119,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":120,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":121,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":122,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":123,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":124,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":125,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":126,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":127,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":128,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":129,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":130,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":131,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":132,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":133,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":134,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":135,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":136,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":137,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":138,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":139,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":140,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":141,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":142,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":143,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":144,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":145,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":146,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":147,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":148,"kind":"mcpp.event","schemaVersion":1,"total":148} +{"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":5,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":6,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":7,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":8,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":9,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":10,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":11,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":12,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":13,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":14,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":15,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":16,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":17,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":18,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":19,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":20,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":21,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":22,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":23,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":24,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":25,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":26,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":27,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":28,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":29,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":30,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":31,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":32,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":33,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":34,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":35,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":36,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":37,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":38,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":39,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":40,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":41,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":42,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":43,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":44,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":45,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":46,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":47,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":48,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":49,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":50,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":51,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":52,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":53,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":54,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":55,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":56,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":57,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":58,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":59,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":60,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":61,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":62,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":63,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":64,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":65,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":66,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":67,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":68,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":69,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":70,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":71,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":72,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":73,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":74,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":75,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":76,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":77,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":78,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":79,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":80,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":81,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":82,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":83,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":84,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":85,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":86,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":87,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":88,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":89,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":90,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":91,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":92,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":93,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":94,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":95,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":96,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":97,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":98,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":99,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":100,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":101,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":102,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":103,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":104,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":105,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":106,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":107,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":108,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":109,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":110,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":111,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":112,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":113,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":114,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":115,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":116,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":117,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":118,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":119,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":120,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":121,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":122,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":123,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":124,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":125,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":126,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":127,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":128,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":129,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":130,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":131,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":132,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":133,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":134,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":135,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":136,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":137,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":138,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":139,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":140,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":141,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":142,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":143,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":144,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":145,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":146,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":147,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":148,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":149,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":150,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":151,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":152,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":153,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":154,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":155,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":156,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":157,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":158,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":159,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":160,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":161,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":162,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":163,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":164,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":165,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":166,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":167,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":168,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":169,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":170,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":171,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":172,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":173,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":174,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":175,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":176,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":177,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":178,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":179,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":180,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":181,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":182,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":183,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":184,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":185,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":186,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":187,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":188,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":189,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":190,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":191,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":192,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":193,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":194,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":195,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":196,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":197,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":198,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":199,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":200,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":201,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":202,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":203,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":204,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":205,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":206,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":207,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":208,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":209,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":210,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":211,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":212,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":213,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":214,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":215,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":216,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":217,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":218,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":219,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":220,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":221,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":222,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":223,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":224,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":225,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":226,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":227,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":228,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":229,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":230,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":231,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":232,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":233,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":234,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":235,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":236,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":237,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":238,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":239,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":240,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":241,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":242,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":243,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":244,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":245,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":246,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":247,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":248,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":249,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":250,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":251,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":252,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":253,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":254,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":255,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":256,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":257,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":258,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":259,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":260,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":261,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":262,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":263,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":264,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":265,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":266,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":267,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":268,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":269,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":270,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":271,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":272,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":273,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":274,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":275,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":276,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":277,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":278,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":279,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":280,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":281,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":282,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":283,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":284,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":285,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":286,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":287,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":288,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":289,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":290,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":291,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":292,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":293,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":294,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":295,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":296,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":297,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":298,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":299,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":300,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":301,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":302,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":303,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":304,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":305,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":306,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":307,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":308,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":309,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":310,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":311,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":312,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":313,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":314,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":315,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":316,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":317,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":318,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":319,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":320,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":321,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":322,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":323,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":324,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":325,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":326,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":327,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":328,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":329,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":330,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":331,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":332,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":333,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":334,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":335,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":336,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":337,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":338,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":339,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":340,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":341,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":342,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":343,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":344,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":345,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":346,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":347,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":348,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":349,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":350,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":351,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":352,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":353,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":354,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":355,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":356,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":357,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":358,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":359,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":360,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":361,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":362,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":363,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":364,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":365,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":366,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":367,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":368,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":369,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":370,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":371,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":372,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":373,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":374,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":375,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":376,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":377,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":378,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":379,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":380,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":381,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":382,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":383,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":384,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":385,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":386,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":387,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":388,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":389,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":390,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":391,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":392,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":393,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":394,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":395,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":396,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":397,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":398,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":399,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":400,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":401,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":402,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":403,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":404,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":405,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":406,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":407,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":408,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":409,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":410,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":411,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":412,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":413,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":414,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":415,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":416,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":417,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":418,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":419,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":420,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":421,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":422,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":423,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":424,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":425,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":426,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":427,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":428,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":429,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":430,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":431,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":432,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":433,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":434,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":435,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":436,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":437,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":438,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":439,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":440,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":441,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":442,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":443,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":444,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":445,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":446,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":447,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":448,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":449,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":450,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":451,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":452,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":453,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":454,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":455,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":456,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":457,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":458,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":459,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":460,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":461,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":462,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":463,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":464,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":465,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":466,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":467,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":468,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":469,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":470,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":471,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":472,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":473,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":474,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":475,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":476,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":477,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":478,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":479,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":480,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":481,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":482,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":483,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":484,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":485,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":486,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":487,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":488,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":489,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":490,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":491,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":492,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":493,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":494,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":495,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":496,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":497,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":498,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":499,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":500,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":501,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":502,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":503,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":504,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":505,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":506,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":507,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":508,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":509,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":510,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":511,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":512,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":513,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":514,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":515,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":516,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":517,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":518,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":519,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":520,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":521,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":522,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":523,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":524,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":525,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":526,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":527,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":528,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":529,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":530,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":531,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":532,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":533,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":534,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":535,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":536,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":537,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":538,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":539,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":540,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":541,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":542,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":543,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":544,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":545,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":546,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":547,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":548,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":549,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":550,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":551,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":552,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":553,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":554,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":555,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":556,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":557,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":558,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":559,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":560,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":561,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":562,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":563,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":564,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":565,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":566,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":567,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":568,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":569,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":570,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":571,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":572,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":573,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":574,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":575,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":576,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":577,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":578,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":579,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":580,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":581,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":582,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":583,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":584,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":585,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":586,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":587,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":588,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":589,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":590,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":591,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":592,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":593,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":594,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":595,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":596,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":597,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":598,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":599,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":600,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":601,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":602,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":603,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":604,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":605,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":606,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":607,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":608,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":609,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":610,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":611,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":612,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":613,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":614,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":615,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":616,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":617,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":618,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":619,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":620,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":621,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":622,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":623,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":624,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":625,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":626,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":627,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":628,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":629,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":630,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":631,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":632,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":633,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":634,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":635,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":636,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":637,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":638,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":639,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":640,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":641,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":642,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":643,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":644,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":645,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":646,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":647,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":648,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":649,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":650,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":651,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":652,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":653,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":654,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":655,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":656,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":657,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":658,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":659,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":660,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":661,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":662,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":663,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":664,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":665,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":666,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":667,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":668,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":669,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":670,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":671,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":672,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":673,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":674,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":675,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":676,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":677,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":678,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":679,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":680,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":681,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":682,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":683,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":684,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":685,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":686,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":687,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":688,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":689,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":690,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":691,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":692,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":693,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":694,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":695,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":696,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":697,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":698,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":699,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":700,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":701,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":702,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":703,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":704,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":705,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":706,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":707,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":708,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":709,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":710,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":711,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":712,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":713,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":714,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":715,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":716,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":717,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":718,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":719,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":720,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":721,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":722,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":723,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":724,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":725,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":726,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":727,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":728,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":729,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":730,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":731,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":732,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":733,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":734,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":735,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":736,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":737,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":738,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":739,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":740,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":741,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":742,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":743,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":744,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":745,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":746,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":747,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":748,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":749,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":750,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":751,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":752,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":753,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":754,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":755,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":756,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":757,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":758,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":759,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":760,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":761,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":762,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":763,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":764,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":765,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":766,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":767,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":768,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":769,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":770,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":771,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":772,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":773,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":774,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":775,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":776,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":777,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":778,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":779,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":780,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":781,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":782,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":783,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":784,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":785,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":786,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":787,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":788,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":789,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":790,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":791,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":792,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":793,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":794,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":795,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":796,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":797,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":798,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":799,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":800,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":801,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":802,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":803,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":804,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":805,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":806,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":807,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":808,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":809,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":810,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":811,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":812,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":813,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":814,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":815,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":816,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":817,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":818,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":819,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":820,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":821,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":822,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":823,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":824,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":825,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":826,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":827,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":828,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":829,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":830,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":831,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":832,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":833,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":834,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":835,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":836,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":837,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":838,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":839,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":840,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":841,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":842,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":843,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":844,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":845,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":846,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":847,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":848,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":849,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":850,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":851,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":852,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":853,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":854,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":855,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":856,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":857,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":858,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":859,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":860,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":861,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":862,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":863,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":864,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":865,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":866,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":867,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":868,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":869,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":870,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":871,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":872,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":873,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":874,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":875,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":876,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":877,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":878,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":879,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":880,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":881,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":882,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":883,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":884,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":885,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":886,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":887,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":888,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":889,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":890,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":891,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":892,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":893,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":894,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":895,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":896,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":897,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":898,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":899,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":900,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":901,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":902,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":903,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":904,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":905,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":906,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":907,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":908,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":909,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":910,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":911,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":912,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":913,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":914,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":915,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":916,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":917,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":918,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":919,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":920,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":921,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":922,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":923,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":924,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":925,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":926,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":927,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":928,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":929,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":930,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":931,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":932,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":933,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":934,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":935,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":936,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":937,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":938,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":939,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":940,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":941,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":942,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":943,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":944,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":945,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":946,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":947,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":948,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":949,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":950,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":951,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":952,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":953,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":954,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":955,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":956,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":957,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":958,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":959,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":960,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":961,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":962,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":963,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":964,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":965,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":966,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":967,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":968,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":969,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":970,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":971,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":972,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":973,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":974,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":975,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":976,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":977,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":978,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":979,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":980,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":981,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":982,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":983,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":984,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":985,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":986,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":987,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":988,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":989,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":990,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":991,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":992,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":993,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":994,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":995,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":996,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":997,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":998,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":999,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1000,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1001,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1002,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1003,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1004,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1005,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1006,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1007,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1008,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1009,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1010,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1011,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1012,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1013,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1014,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1015,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1016,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1017,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1018,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1019,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1020,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1021,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1022,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1023,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1024,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1025,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1026,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1027,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1028,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1029,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1030,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1031,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1032,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1033,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1034,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1035,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1036,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1037,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1038,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1039,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1040,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1041,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1042,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1043,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1044,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1045,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1046,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1047,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1048,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1049,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1050,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1051,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1052,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1053,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1054,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1055,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1056,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1057,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1058,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1059,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1060,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1061,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1062,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1063,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1064,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1065,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1066,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1067,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1068,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1069,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1070,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1071,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1072,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1073,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1074,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1075,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1076,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1077,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1078,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1079,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1080,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1081,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1082,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1083,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1084,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1085,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1086,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1087,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1088,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1089,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1090,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1091,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1092,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1093,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1094,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1095,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1096,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1097,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1098,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1099,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1100,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1101,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1102,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1103,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1104,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1105,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1106,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1107,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1108,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1109,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1110,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1111,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1112,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1113,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1114,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1115,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1116,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1117,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1118,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1119,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1120,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1121,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1122,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1123,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1124,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1125,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1126,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1127,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1128,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1129,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1130,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1131,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1132,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1133,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1134,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1135,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1136,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1137,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1138,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1139,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1140,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1141,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1142,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1143,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1144,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1145,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1146,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1147,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1148,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1149,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1150,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1151,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1152,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1153,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1154,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1155,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1156,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1157,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1158,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1159,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1160,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1161,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1162,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1163,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1164,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1165,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1166,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1167,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1168,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1169,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1170,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1171,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1172,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1173,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1174,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1175,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1176,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1177,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1178,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1179,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1180,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1181,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1182,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1183,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1184,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1185,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1186,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1187,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1188,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1189,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1190,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1191,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1192,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1193,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1194,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1195,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1196,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1197,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1198,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1199,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1200,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1201,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1202,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1203,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1204,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1205,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1206,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1207,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1208,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1209,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1210,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1211,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1212,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1213,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1214,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1215,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1216,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1217,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1218,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1219,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1220,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1221,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1222,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1223,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1224,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1225,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1226,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1227,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1228,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1229,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1230,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1231,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1232,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1233,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1234,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1235,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1236,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1237,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1238,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1239,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1240,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1241,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1242,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1243,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1244,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1245,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1246,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1247,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1248,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1249,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1250,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1251,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1252,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1253,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1254,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1255,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1256,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1257,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1258,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1259,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1260,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1261,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1262,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1263,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1264,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1265,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1266,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1267,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1268,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1269,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1270,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1271,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1272,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1273,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1274,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1275,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1276,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1277,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1278,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1279,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1280,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1281,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1282,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1283,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1284,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1285,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1286,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1287,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1288,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1289,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1290,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1291,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1292,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1293,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1294,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1295,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1296,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1297,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1298,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1299,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1300,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1301,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1302,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1303,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1304,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1305,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1306,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1307,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1308,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1309,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1310,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1311,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1312,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1313,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1314,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1315,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1316,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1317,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1318,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1319,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1320,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1321,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1322,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1323,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1324,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1325,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1326,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1327,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1328,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1329,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1330,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1331,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1332,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1333,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1334,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1335,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1336,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1337,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1338,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1339,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1340,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1341,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1342,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1343,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1344,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1345,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1346,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1347,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1348,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1349,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1350,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1351,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1352,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1353,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1354,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1355,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1356,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1357,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1358,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1359,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1360,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1361,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1362,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1363,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1364,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1365,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1366,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1367,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1368,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1369,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1370,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1371,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1372,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1373,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1374,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1375,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1376,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1377,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1378,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1379,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1380,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1381,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1382,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1383,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1384,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1385,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1386,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1387,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1388,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1389,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1390,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1391,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1392,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1393,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1394,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1395,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1396,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1397,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1398,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1399,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1400,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1401,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1402,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1403,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1404,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1405,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1406,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1407,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1408,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1409,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1410,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1411,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1412,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1413,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1414,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1415,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1416,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1417,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1418,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1419,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1420,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1421,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1422,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1423,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1424,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1425,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1426,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1427,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1428,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1429,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1430,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1431,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1432,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1433,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1434,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1435,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1436,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1437,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1438,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1439,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1440,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1441,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1442,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1443,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1444,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1445,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1446,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1447,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1448,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1449,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1450,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1451,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1452,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1453,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1454,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1455,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1456,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1457,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1458,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1459,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1460,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1461,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1462,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1463,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1464,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1465,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1466,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1467,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1468,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1469,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1470,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1471,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1472,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1473,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1474,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1475,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1476,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1477,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1478,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1479,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1480,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1481,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1482,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1483,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1484,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1485,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1486,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1487,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1488,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1489,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1490,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1491,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1492,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1493,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1494,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1495,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1496,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1497,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1498,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1499,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1500,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1501,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1502,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1503,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1504,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1505,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1506,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1507,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1508,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1509,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1510,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1511,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1512,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1513,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1514,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1515,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1516,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1517,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1518,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1519,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1520,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1521,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1522,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1523,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1524,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1525,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1526,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1527,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1528,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1529,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1530,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1531,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1532,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1533,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1534,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1535,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1536,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1537,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1538,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1539,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1540,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1541,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1542,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1543,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1544,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1545,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1546,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1547,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1548,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1549,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1550,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1551,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1552,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1553,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1554,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1555,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1556,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1557,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1558,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1559,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1560,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1561,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1562,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1563,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1564,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1565,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1566,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1567,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1568,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1569,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1570,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1571,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1572,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1573,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1574,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1575,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1576,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1577,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1578,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1579,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1580,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1581,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1582,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1583,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1584,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1585,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1586,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1587,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1588,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1589,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1590,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1591,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1592,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1593,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1594,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1595,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1596,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1597,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1598,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1599,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1600,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1601,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1602,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1603,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1604,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1605,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1606,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1607,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1608,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1609,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1610,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1611,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1612,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1613,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1614,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1615,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1616,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1617,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1618,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1619,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1620,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1621,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1622,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1623,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1624,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1625,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1626,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1627,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1628,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1629,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1630,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1631,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1632,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1633,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1634,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1635,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1636,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1637,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1638,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1639,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1640,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1641,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1642,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1643,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1644,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1645,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1646,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1647,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1648,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1649,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1650,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1651,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1652,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1653,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1654,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1655,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1656,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1657,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1658,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1659,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1660,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1661,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1662,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1663,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1664,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1665,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1666,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1667,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1668,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1669,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1670,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1671,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1672,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1673,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1674,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1675,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1676,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1677,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1678,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1679,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1680,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1681,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1682,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1683,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1684,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1685,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1686,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1687,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1688,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1689,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1690,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1691,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1692,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1693,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1694,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1695,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1696,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"event":"progress","finished":1697,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"artifact":{"kind":"bin","launch":{"argv":[],"cwd":"@ROOT@","env":{},"via":"runner"},"name":"app","path":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9/bin/app.oke"},"event":"artifact","kind":"mcpp.event","schemaVersion":1} +{"data":{"artifacts":[{"kind":"bin","launch":{"argv":[],"cwd":"@ROOT@","env":{},"via":"runner"},"name":"app","path":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9/bin/app.oke"}],"client":"mcpp-ide-fixtures","command":"mcpp build --target aarch64-openkal --message-format json","compileDatabase":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9/compile_commands.json","configuration":{"fingerprint":"38fc4cae0272ddf9","hostPlatform":null,"outputDir":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9","platform":{"fields":{"carrier":{"source":"platform","value":"openkal-run@0.1.3"},"layers.c++-abi":{"source":"platform","value":"openkal-llvm-runtime@0.16.5"},"layers.c-abi":{"source":"platform","value":"openkal-musl@0.22.5"},"layers.compiler-runtime":{"source":"platform","value":"openkal-llvm-runtime@0.16.5"},"link.driver":{"source":"platform","value":"lld"},"link.exe":{"source":"platform","value":"{name}.oke"},"link.shared":{"source":"platform","value":"lib{name}.okso"},"link.start":{"source":"platform","value":"ok_main"},"runner":{"source":"platform","value":["okrun","{}"]},"toolchain":{"source":"platform","value":"llvm@23.1.3"},"tools.okld":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/0daa33111e083da8/bin/okld"},"tools.okrun":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/3e48df0058ef2949/bin/okrun"}},"hosted":false,"name":"openkal-platform","source":"built-in","version":"0.17.2"},"profile":"dev","triple":"aarch64-openkal"},"diagnostics":[],"finishedAt":1793148661130,"pid":1204344,"startedAt":1793148653933,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} diff --git a/protocol/fixtures/cache-list.json b/protocol/fixtures/cache-list.json index 354f857..8b93fbd 100644 --- a/protocol/fixtures/cache-list.json +++ b/protocol/fixtures/cache-list.json @@ -2,7 +2,7 @@ "data": { "entries": [ { - "accessed": 1793071043, + "accessed": 1793135706, "bytes": 2808, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/26916f34b8cd3aed", @@ -12,7 +12,7 @@ "label": "local-dev/local-dev.gfx-runtime@1.0.0" }, { - "accessed": 1793071043, + "accessed": 1793135706, "bytes": 4688, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/27e4d0283d6e95aa", @@ -22,7 +22,7 @@ "label": "local-dev/local-dev.gfx-runtime@1.0.0" }, { - "accessed": 1793071043, + "accessed": 1793135706, "bytes": 2792, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/07829ab3ec4688f8", @@ -32,37 +32,27 @@ "label": "local-dev/local-dev.gfx-runtime@1.0.0" }, { - "accessed": 1793032871, - "bytes": 4161448, + "accessed": 1793132038, + "bytes": 4165240, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/ac258dcd248798bf", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/2dbdd2932bb35cc8", "files": 109, - "key": "ac258dcd248798bf", + "key": "2dbdd2932bb35cc8", "kind": "pkg", "label": "compat/compat.mbedtls@3.6.1" }, { - "accessed": 1793030032, - "bytes": 4161448, + "accessed": 1793148437, + "bytes": 4165240, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/2b62ed5aedbb0c90", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/40557c641c314332", "files": 109, - "key": "2b62ed5aedbb0c90", + "key": "40557c641c314332", "kind": "pkg", "label": "compat/compat.mbedtls@3.6.1" }, { - "accessed": 1793118305, - "bytes": 4165216, - "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/c4f67483e585bf28", - "files": 109, - "key": "c4f67483e585bf28", - "kind": "pkg", - "label": "compat/compat.mbedtls@3.6.1" - }, - { - "accessed": 1793064906, + "accessed": 1793140254, "bytes": 1248, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/4bd055d3e639f838", @@ -72,334 +62,344 @@ "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1793045336, - "bytes": 2960, + "accessed": 1793146687, + "bytes": 2952, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/1212e78f9ca6f89b", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/57a40b9605feaaee", "files": 2, - "key": "1212e78f9ca6f89b", + "key": "57a40b9605feaaee", "kind": "pkg", "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1793045090, - "bytes": 1248, + "accessed": 1793146687, + "bytes": 558088, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/0dd55b9dcbefef55", - "files": 2, - "key": "0dd55b9dcbefef55", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/c1bb7e4064dba71b", + "files": 12, + "key": "c1bb7e4064dba71b", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1793116930, - "bytes": 3256, + "accessed": 1793140254, + "bytes": 200600, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/8162763afcdefca8", - "files": 2, - "key": "8162763afcdefca8", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/6b051e0a97b8b911", + "files": 12, + "key": "6b051e0a97b8b911", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xcb@1.17.0" }, { - "accessed": 1793031941, - "bytes": 2952, + "accessed": 1793140254, + "bytes": 124248, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/b9cc3b9317e9ff85", - "files": 2, - "key": "b9cc3b9317e9ff85", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xext@1.3.7/5d5012bbf64f13e6", + "files": 18, + "key": "5d5012bbf64f13e6", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xext@1.3.7" }, { - "accessed": 1793053112, - "bytes": 2936, + "accessed": 1793146687, + "bytes": 935896, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/329610f00b3d2509", - "files": 2, - "key": "329610f00b3d2509", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xext@1.3.7/86e10bc0a9eb4db6", + "files": 18, + "key": "86e10bc0a9eb4db6", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xext@1.3.7" }, { - "accessed": 1793115868, - "bytes": 3280, + "accessed": 1793148082, + "bytes": 736888, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/fd9e8ec519362697", - "files": 2, - "key": "fd9e8ec519362697", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.zstd@1.5.7/b3371f11886433a0", + "files": 27, + "key": "b3371f11886433a0", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.zstd@1.5.7" }, { - "accessed": 1793045442, - "bytes": 2952, + "accessed": 1793147496, + "bytes": 737456, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/dc0c93e76254d2a5", - "files": 2, - "key": "dc0c93e76254d2a5", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.zstd@1.5.7/1bc50801f90769da", + "files": 27, + "key": "1bc50801f90769da", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.zstd@1.5.7" }, { - "accessed": 1793033974, - "bytes": 2968, + "accessed": 1793148437, + "bytes": 4267480, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/aab54974d9d305e9", - "files": 2, - "key": "aab54974d9d305e9", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.zstd@1.5.7/3e322a18ff50d93f", + "files": 27, + "key": "3e322a18ff50d93f", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.zstd@1.5.7" }, { - "accessed": 1793074379, - "bytes": 2960, + "accessed": 1793132038, + "bytes": 4267480, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/5af9be881da9ccc8", - "files": 2, - "key": "5af9be881da9ccc8", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.zstd@1.5.7/71d42574ae2a40fd", + "files": 27, + "key": "71d42574ae2a40fd", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.zstd@1.5.7" }, { - "accessed": 1793064836, - "bytes": 1248, + "accessed": 1793148628, + "bytes": 3458384, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/f9c3d1a8a7876dbe", - "files": 2, - "key": "f9c3d1a8a7876dbe", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.freetype@2.13.3/32588b37a58c1fdf", + "files": 43, + "key": "32588b37a58c1fdf", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.freetype@2.13.3" }, { - "accessed": 1793043363, - "bytes": 1248, + "accessed": 1793140254, + "bytes": 1047992, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/aa1597a4809bded3", - "files": 2, - "key": "aa1597a4809bded3", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.freetype@2.13.3/9504b2c99e125a56", + "files": 43, + "key": "9504b2c99e125a56", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.freetype@2.13.3" }, { - "accessed": 1793031127, - "bytes": 3232, + "accessed": 1793126757, + "bytes": 4475680, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/975707438b5b5b4a", - "files": 2, - "key": "975707438b5b5b4a", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.freetype@2.13.3/45c016730cbedaad", + "files": 43, + "key": "45c016730cbedaad", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.freetype@2.13.3" }, { - "accessed": 1793031200, - "bytes": 2952, + "accessed": 1793145509, + "bytes": 925584, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/bb6a79adc3f59398", - "files": 2, - "key": "bb6a79adc3f59398", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.gtest@1.15.2/2acd640e7d91e5bd", + "files": 3, + "key": "2acd640e7d91e5bd", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.gtest@1.15.2" }, { - "accessed": 1793118326, - "bytes": 2952, + "accessed": 1793140254, + "bytes": 2197648, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/57a40b9605feaaee", - "files": 2, - "key": "57a40b9605feaaee", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.x11@1.8.13/770b5190ca6bd2d9", + "files": 411, + "key": "770b5190ca6bd2d9", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.x11@1.8.13" }, { - "accessed": 1793111430, - "bytes": 3216, + "accessed": 1793146687, + "bytes": 21818960, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/22b7542e5cadbce7", - "files": 2, - "key": "22b7542e5cadbce7", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.x11@1.8.13/cb343939501cb4ce", + "files": 411, + "key": "cb343939501cb4ce", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.x11@1.8.13" }, { - "accessed": 1793117862, - "bytes": 2960, + "accessed": 1793132038, + "bytes": 188464, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/403a28faa71cca77", - "files": 2, - "key": "403a28faa71cca77", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.bzip2@1.0.8/bdee22498cbb42be", + "files": 8, + "key": "bdee22498cbb42be", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.bzip2@1.0.8" }, { - "accessed": 1793115843, - "bytes": 3232, + "accessed": 1793148437, + "bytes": 188464, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/17e2feb6e3f0147c", - "files": 2, - "key": "17e2feb6e3f0147c", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.bzip2@1.0.8/bb26e20da52e1540", + "files": 8, + "key": "bb26e20da52e1540", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.bzip2@1.0.8" }, { - "accessed": 1793033076, - "bytes": 2952, + "accessed": 1793140254, + "bytes": 1248, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/e0ede14d540cc89c", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xtrans@1.6.0/b666a53f5aedaff3", "files": 2, - "key": "e0ede14d540cc89c", + "key": "b666a53f5aedaff3", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xtrans@1.6.0" }, { - "accessed": 1793045143, - "bytes": 3232, + "accessed": 1793146687, + "bytes": 2944, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/c0da81c79980dd9f", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xtrans@1.6.0/cc8eefe29166f0d1", "files": 2, - "key": "c0da81c79980dd9f", + "key": "cc8eefe29166f0d1", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xtrans@1.6.0" }, { - "accessed": 1793118278, - "bytes": 2952, + "accessed": 1793146687, + "bytes": 2911064, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/bd610edac4ea7d69", - "files": 2, - "key": "bd610edac4ea7d69", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xi@1.8.3/44574f0fb23f9cb7", + "files": 58, + "key": "44574f0fb23f9cb7", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.xi@1.8.3" }, { - "accessed": 1793033587, - "bytes": 2952, + "accessed": 1793140254, + "bytes": 172032, + "complete": true, + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xi@1.8.3/360c0aaa41a615c5", + "files": 58, + "key": "360c0aaa41a615c5", + "kind": "pkg", + "label": "compat/compat.xi@1.8.3" + }, + { + "accessed": 1793148628, + "bytes": 2960, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/b42a151c1ec3d74f", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.concurrentqueue@1.0.5/34eab8a84521d53d", "files": 2, - "key": "b42a151c1ec3d74f", + "key": "34eab8a84521d53d", "kind": "pkg", - "label": "compat/compat.xorgproto@2025.1" + "label": "compat/compat.concurrentqueue@1.0.5" }, { - "accessed": 1793043269, - "bytes": 641776, + "accessed": 1793126635, + "bytes": 3272, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/ba17d9e31fb7f3e5", - "files": 12, - "key": "ba17d9e31fb7f3e5", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.concurrentqueue@1.0.5/09177842e8f38d34", + "files": 2, + "key": "09177842e8f38d34", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.concurrentqueue@1.0.5" }, { - "accessed": 1793118326, - "bytes": 558088, + "accessed": 1793140254, + "bytes": 1256, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/c1bb7e4064dba71b", - "files": 12, - "key": "c1bb7e4064dba71b", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.concurrentqueue@1.0.5/2130b22bd8a430af", + "files": 2, + "key": "2130b22bd8a430af", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.concurrentqueue@1.0.5" }, { - "accessed": 1793117862, - "bytes": 558136, + "accessed": 1793126757, + "bytes": 3272, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/6d496360aad37545", - "files": 12, - "key": "6d496360aad37545", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.concurrentqueue@1.0.5/c7de98ad3de4ab2b", + "files": 2, + "key": "c7de98ad3de4ab2b", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.concurrentqueue@1.0.5" }, { - "accessed": 1793033587, - "bytes": 558088, + "accessed": 1793126634, + "bytes": 2960, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/58f4b5f38eefa669", - "files": 12, - "key": "58f4b5f38eefa669", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.concurrentqueue@1.0.5/42615a65074f0572", + "files": 2, + "key": "42615a65074f0572", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.concurrentqueue@1.0.5" }, { - "accessed": 1793045153, - "bytes": 641776, + "accessed": 1793146687, + "bytes": 600504, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/68df645b652e834a", - "files": 12, - "key": "68df645b652e834a", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xrandr@1.5.5/380ade378dbdd108", + "files": 11, + "key": "380ade378dbdd108", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.xrandr@1.5.5" }, { - "accessed": 1793074379, - "bytes": 558160, + "accessed": 1793140254, + "bytes": 69240, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/e6d6a48daf30b262", - "files": 12, - "key": "e6d6a48daf30b262", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xrandr@1.5.5/f10ce4331e8af46e", + "files": 11, + "key": "f10ce4331e8af46e", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.xrandr@1.5.5" }, { - "accessed": 1793031200, - "bytes": 558088, + "accessed": 1793140254, + "bytes": 1240, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/64da9b2a564c56ce", - "files": 12, - "key": "64da9b2a564c56ce", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb-proto@1.17.0/c44783365d0c5293", + "files": 2, + "key": "c44783365d0c5293", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.xcb-proto@1.17.0" }, { - "accessed": 1793064906, - "bytes": 200600, + "accessed": 1793146687, + "bytes": 2944, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/6b051e0a97b8b911", - "files": 12, - "key": "6b051e0a97b8b911", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb-proto@1.17.0/d8f80c93fb43d75d", + "files": 2, + "key": "d8f80c93fb43d75d", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.xcb-proto@1.17.0" }, { - "accessed": 1793030359, - "bytes": 558120, + "accessed": 1793126757, + "bytes": 1015872, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/e50868c6827dcec0", - "files": 12, - "key": "e50868c6827dcec0", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libpng@1.6.43/06a18e1c02086029", + "files": 16, + "key": "06a18e1c02086029", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.libpng@1.6.43" }, { - "accessed": 1793044985, - "bytes": 558088, + "accessed": 1793148628, + "bytes": 800112, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/9588ad68bcf26d15", - "files": 12, - "key": "9588ad68bcf26d15", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libpng@1.6.43/9d5fda8f3e1cf7e9", + "files": 16, + "key": "9d5fda8f3e1cf7e9", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.libpng@1.6.43" }, { - "accessed": 1793053112, - "bytes": 704184, + "accessed": 1793140254, + "bytes": 346240, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/0639bd78ab4d2be9", - "files": 12, - "key": "0639bd78ab4d2be9", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libpng@1.6.43/8b37498564545e91", + "files": 16, + "key": "8b37498564545e91", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.libpng@1.6.43" }, { - "accessed": 1793033974, - "bytes": 558216, + "accessed": 1793140254, + "bytes": 60576, "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/cfbe3199c7e4e098", - "files": 12, - "key": "cfbe3199c7e4e098", + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xrender@0.9.12/6d16c726588807b8", + "files": 14, + "key": "6d16c726588807b8", "kind": "pkg", - "label": "compat/compat.xcb@1.17.0" + "label": "compat/compat.xrender@0.9.12" } ], "root": "@HOME@/.mcpp/build-cache/v1" @@ -413,7 +413,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/index-list.json b/protocol/fixtures/index-list.json index a77da76..10111c3 100644 --- a/protocol/fixtures/index-list.json +++ b/protocol/fixtures/index-list.json @@ -21,7 +21,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/launch.json b/protocol/fixtures/launch.json index d3f7212..260a83c 100644 --- a/protocol/fixtures/launch.json +++ b/protocol/fixtures/launch.json @@ -1,7 +1,7 @@ { "data": { "argv": [ - "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app" + "@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app" ], "cwd": "@ROOT@", "env": { @@ -10,7 +10,7 @@ "XDG_DATA_DIRS": "@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop", "__EGL_VENDOR_LIBRARY_DIRS": "@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d" }, - "program": "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app", + "program": "@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app", "via": null }, "diagnostics": [], @@ -25,7 +25,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/pack-formats.json b/protocol/fixtures/pack-formats.json index 8bc6c2a..3bca6ad 100644 --- a/protocol/fixtures/pack-formats.json +++ b/protocol/fixtures/pack-formats.json @@ -27,7 +27,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/pack-help.txt b/protocol/fixtures/pack-help.txt index c4e56af..af14acf 100644 --- a/protocol/fixtures/pack-help.txt +++ b/protocol/fixtures/pack-help.txt @@ -6,15 +6,23 @@ USAGE: mcpp pack <target> OPTIONS: - --mode system | vendored (default) | self-contained | static + --mode What the machine that runs it provides: system | vendored (default) | self-contained | static (= --linkage static --mode self-contained) + --linkage <static|shared> The program's libraries in it (static) or beside it (shared); rebuilds with [build] dependency_linkage (default: as the project builds) --target Triple, e.g. x86_64-linux-musl (repeatable: one leg per triple) - --format tar (default; .zip for a Windows target) | dir | any format the resolved graph provides (e.g. appimage, msi) + --no-universal Pack the selected target alone where its platform packs all its targets into one universal package + --systems <LIST> Self-contained universal package: the systems whose loaders it carries (linux,macos,windows; default: this machine's) + --compress <ALG[:LEVEL]> The container's compression: gzip (tar default) | zstd | xz | none; a zip deflates unless none + --merge <PACKAGE> Merge packages this command wrote (universal legs, systems) into one; repeatable, nothing is built + --pkg-format <FORMAT> The package format: tar | zip | dir | single-file | any format the resolved graph provides (e.g. appimage, msi, okb); default: zip for a Windows program, tar elsewhere + --format Earlier spelling of --pkg-format -o, --output Override output path; with several members, the directory each archive or tree is written below --profile Build profile (default: [build] default-profile, else release) --release Shorthand for --profile release --dev Shorthand for --profile dev --toolchain <SPEC> Build with this toolchain for one invocation, e.g. llvm@22.1.8 --sysroot <SYSROOT> The target's base for this invocation (= MCPP_SYSROOT): a package, glibc@system, path:<dir>, none + --platform <SPEC> The target's platform for this invocation (= MCPP_PLATFORM): <name>@<version>, path:<dir>, none + --host-platform <SPEC> The host graph's platform for this invocation (= MCPP_HOST_PLATFORM) --features <LIST> Activate root-package features, and a dependency's as <dependency>/<feature>, for every build pass of the pack (comma-separated) --list-formats Print the formats --format accepts here, the engine's and those the resolved graph provides, as the mcpp.pack.formats envelope --message-format <FMT> Output format: human (default) | json (one mcpp.pack envelope on stdout; narration on stderr) diff --git a/protocol/fixtures/protocol-version.json b/protocol/fixtures/protocol-version.json index c12f108..8015d01 100644 --- a/protocol/fixtures/protocol-version.json +++ b/protocol/fixtures/protocol-version.json @@ -114,7 +114,7 @@ "mcpp.xpkg": 1 }, "mcpp": { - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/result-ok.json b/protocol/fixtures/result-ok.json index f75dcad..17d2b02 100644 --- a/protocol/fixtures/result-ok.json +++ b/protocol/fixtures/result-ok.json @@ -5,7 +5,7 @@ "kind": "bin", "launch": { "argv": [ - "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app" + "@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app" ], "cwd": "@ROOT@", "env": { @@ -17,28 +17,30 @@ "via": null }, "name": "app", - "path": "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/bin/app" + "path": "@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app" } ], "client": "mcpp-ide-fixtures", "command": "mcpp build --message-format json", - "compileDatabase": "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30/compile_commands.json", + "compileDatabase": "@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/compile_commands.json", "configuration": { - "fingerprint": "b4dbdb186bc3ef30", - "outputDir": "@ROOT@/target/x86_64-linux-gnu/b4dbdb186bc3ef30", + "fingerprint": "77ba4e6c37abd416", + "hostPlatform": null, + "outputDir": "@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416", + "platform": null, "profile": "dev", "triple": "x86_64-linux-gnu" }, "diagnostics": [], - "finishedAt": 1793118343698, - "pid": 1767942, - "startedAt": 1793118343022, + "finishedAt": 1793148650353, + "pid": 1203929, + "startedAt": 1793148649554, "status": "ok" }, "kind": "mcpp.result", "kindVersion": 1, "mcpp": { - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/search.json b/protocol/fixtures/search.json index 9dfce35..f19c4e9 100644 --- a/protocol/fixtures/search.json +++ b/protocol/fixtures/search.json @@ -853,7 +853,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/self-env.json b/protocol/fixtures/self-env.json index 165eaa0..37e2c21 100644 --- a/protocol/fixtures/self-env.json +++ b/protocol/fixtures/self-env.json @@ -4,12 +4,12 @@ "buildCache": "@HOME@/.mcpp/build-cache/v1", "config": "@HOME@/.mcpp/config.toml", "defaultToolchain": "gcc@16.1.0", - "engineModules": "@HOME@/.mcpp/engine/2026.10.26.2/modules", + "engineModules": "@HOME@/.mcpp/engine/2026.10.27.1/modules", "homeLocator": "", "homeSource": "user", "initialized": true, "mcppHome": "@HOME@/.mcpp", - "mcppVersion": "2026.10.26.2", + "mcppVersion": "2026.10.27.1", "originalHome": "@HOME@/.mcpp", "registry": "@HOME@/.mcpp/registry", "xlingsBinary": "@HOME@/.mcpp/registry/bin/xlings", @@ -24,7 +24,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/test.ndjson b/protocol/fixtures/test.ndjson index ebcea38..11bf575 100644 --- a/protocol/fixtures/test.ndjson +++ b/protocol/fixtures/test.ndjson @@ -1,2 +1,2 @@ -{"member":"","test":"test_smoke","status":"pass","exit_code":0,"signal":null,"duration_ms":2,"timed_out":false,"compile_output":"","run_output":"test_smoke: ok\n","reason":"","build_ms":616} -{"summary":{"member":"","passed":1,"failed":0,"not_run":0,"not_run_reason":"","built":0,"elapsed_ms":778,"build_ms":672,"run_ms":2}} +{"member":"","test":"test_smoke","status":"pass","exit_code":0,"signal":null,"duration_ms":3,"timed_out":false,"compile_output":"","run_output":"test_smoke: ok\n","reason":"","build_ms":680} +{"summary":{"member":"","passed":1,"failed":0,"not_run":0,"not_run_reason":"","built":0,"elapsed_ms":943,"build_ms":741,"run_ms":3}} diff --git a/protocol/fixtures/toolchain-list-platform.json b/protocol/fixtures/toolchain-list-platform.json new file mode 100644 index 0000000..693c278 --- /dev/null +++ b/protocol/fixtures/toolchain-list-platform.json @@ -0,0 +1,314 @@ +{ + "data": { + "host": "x86_64-linux-gnu", + "targets": [ + { + "default": false, + "note": "static, cross", + "pin": "gcc@16.1.0", + "platform": null, + "status": "installed", + "target": "aarch64-linux-musl", + "toolchain": "gcc 16.1.0" + }, + { + "default": false, + "note": "host", + "pin": "", + "platform": null, + "status": "installed", + "target": "x86_64-linux-gnu", + "toolchain": "gcc 15.1.0" + }, + { + "default": true, + "note": "host", + "pin": "", + "platform": null, + "status": "installed", + "target": "x86_64-linux-gnu", + "toolchain": "gcc 16.1.0" + }, + { + "default": false, + "note": "host", + "pin": "", + "platform": null, + "status": "installed", + "target": "x86_64-linux-gnu", + "toolchain": "llvm 22.1.8" + }, + { + "default": false, + "note": "host", + "pin": "", + "platform": null, + "status": "installed", + "target": "x86_64-linux-gnu", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "static", + "pin": "gcc@16.1.0", + "platform": null, + "status": "installed", + "target": "x86_64-linux-musl", + "toolchain": "gcc 16.1.0" + }, + { + "default": false, + "note": "static", + "pin": "gcc@16.1.0", + "platform": null, + "status": "installed", + "target": "x86_64-linux-musl", + "toolchain": "gcc 15.1.0" + }, + { + "default": false, + "note": "PE, static, cross", + "pin": "gcc@16.1.0", + "platform": null, + "status": "installed", + "target": "x86_64-windows-gnu", + "toolchain": "gcc 16.1.0" + }, + { + "default": false, + "note": "cross", + "pin": "android-ndk@30.0.16248370", + "platform": null, + "status": "available", + "target": "aarch64-linux-android", + "toolchain": "android-ndk 30.0.16248370" + }, + { + "default": false, + "note": "cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "via dependency graph", + "target": "aarch64-linux-gnu", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "aarch64-none-elf", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "ok, static, cross", + "pin": "llvm@23.1.3", + "platform": "mcpplibs.openkal-platform@0.17.2", + "status": "available", + "target": "aarch64-openkal", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "armv7a-none-eabi", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "armv7a-none-eabihf", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "riscv32-none-elf", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "riscv64-none-elf", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "thumbv6m-none-eabi", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "thumbv7em-none-eabi", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "thumbv7em-none-eabihf", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "thumbv7m-none-eabi", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "thumbv8m.base-none-eabi", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "thumbv8m.main-none-eabi", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "thumbv8m.main-none-eabihf", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "wasm, static, cross", + "pin": "emsdk@6.0.9", + "platform": null, + "status": "available", + "target": "wasm32-emscripten", + "toolchain": "emsdk 6.0.9" + }, + { + "default": false, + "note": "cross", + "pin": "android-ndk@30.0.16248370", + "platform": null, + "status": "available", + "target": "x86_64-linux-android", + "toolchain": "android-ndk 30.0.16248370" + }, + { + "default": false, + "note": "bare, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "available", + "target": "x86_64-none-elf", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "ok, static, cross", + "pin": "llvm@23.1.3", + "platform": "mcpplibs.openkal-platform@0.17.2", + "status": "available", + "target": "x86_64-openkal", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "PE, static, cross", + "pin": "llvm@23.1.3", + "platform": null, + "status": "via dependency graph", + "target": "x86_64-windows-musl", + "toolchain": "llvm 23.1.3" + }, + { + "default": false, + "note": "static, cross", + "pin": "", + "platform": null, + "status": "planned", + "target": "riscv64-linux-musl", + "toolchain": "—" + }, + { + "default": false, + "note": "cross", + "pin": "", + "platform": null, + "status": "planned", + "target": "x86_64-macos", + "toolchain": "—" + } + ], + "toolchains": [ + { + "default": true, + "family": "gcc", + "version": "16.1.0" + }, + { + "default": false, + "family": "gcc", + "version": "15.1.0" + }, + { + "default": false, + "family": "llvm", + "version": "23.1.3" + }, + { + "availableRevision": 1, + "default": false, + "family": "llvm", + "installedRevision": 0, + "usable": true, + "version": "22.1.8" + } + ] + }, + "diagnostics": [], + "effects": [], + "kind": "mcpp.toolchain.list", + "kindVersion": 1, + "mcpp": { + "protocol": { + "max": 1, + "min": 1 + }, + "version": "2026.10.27.1" + }, + "schemaVersion": 1 +} diff --git a/protocol/fixtures/toolchain-list.json b/protocol/fixtures/toolchain-list.json index b9d72e1..693c278 100644 --- a/protocol/fixtures/toolchain-list.json +++ b/protocol/fixtures/toolchain-list.json @@ -6,6 +6,7 @@ "default": false, "note": "static, cross", "pin": "gcc@16.1.0", + "platform": null, "status": "installed", "target": "aarch64-linux-musl", "toolchain": "gcc 16.1.0" @@ -14,6 +15,7 @@ "default": false, "note": "host", "pin": "", + "platform": null, "status": "installed", "target": "x86_64-linux-gnu", "toolchain": "gcc 15.1.0" @@ -22,6 +24,7 @@ "default": true, "note": "host", "pin": "", + "platform": null, "status": "installed", "target": "x86_64-linux-gnu", "toolchain": "gcc 16.1.0" @@ -30,6 +33,7 @@ "default": false, "note": "host", "pin": "", + "platform": null, "status": "installed", "target": "x86_64-linux-gnu", "toolchain": "llvm 22.1.8" @@ -38,6 +42,7 @@ "default": false, "note": "host", "pin": "", + "platform": null, "status": "installed", "target": "x86_64-linux-gnu", "toolchain": "llvm 23.1.3" @@ -46,6 +51,7 @@ "default": false, "note": "static", "pin": "gcc@16.1.0", + "platform": null, "status": "installed", "target": "x86_64-linux-musl", "toolchain": "gcc 16.1.0" @@ -54,6 +60,7 @@ "default": false, "note": "static", "pin": "gcc@16.1.0", + "platform": null, "status": "installed", "target": "x86_64-linux-musl", "toolchain": "gcc 15.1.0" @@ -62,6 +69,7 @@ "default": false, "note": "PE, static, cross", "pin": "gcc@16.1.0", + "platform": null, "status": "installed", "target": "x86_64-windows-gnu", "toolchain": "gcc 16.1.0" @@ -70,6 +78,7 @@ "default": false, "note": "cross", "pin": "android-ndk@30.0.16248370", + "platform": null, "status": "available", "target": "aarch64-linux-android", "toolchain": "android-ndk 30.0.16248370" @@ -78,6 +87,7 @@ "default": false, "note": "cross", "pin": "llvm@23.1.3", + "platform": null, "status": "via dependency graph", "target": "aarch64-linux-gnu", "toolchain": "llvm 23.1.3" @@ -86,6 +96,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "aarch64-none-elf", "toolchain": "llvm 23.1.3" @@ -94,6 +105,7 @@ "default": false, "note": "ok, static, cross", "pin": "llvm@23.1.3", + "platform": "mcpplibs.openkal-platform@0.17.2", "status": "available", "target": "aarch64-openkal", "toolchain": "llvm 23.1.3" @@ -102,6 +114,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "armv7a-none-eabi", "toolchain": "llvm 23.1.3" @@ -110,6 +123,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "armv7a-none-eabihf", "toolchain": "llvm 23.1.3" @@ -118,6 +132,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "riscv32-none-elf", "toolchain": "llvm 23.1.3" @@ -126,6 +141,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "riscv64-none-elf", "toolchain": "llvm 23.1.3" @@ -134,6 +150,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "thumbv6m-none-eabi", "toolchain": "llvm 23.1.3" @@ -142,6 +159,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "thumbv7em-none-eabi", "toolchain": "llvm 23.1.3" @@ -150,6 +168,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "thumbv7em-none-eabihf", "toolchain": "llvm 23.1.3" @@ -158,6 +177,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "thumbv7m-none-eabi", "toolchain": "llvm 23.1.3" @@ -166,6 +186,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "thumbv8m.base-none-eabi", "toolchain": "llvm 23.1.3" @@ -174,6 +195,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "thumbv8m.main-none-eabi", "toolchain": "llvm 23.1.3" @@ -182,6 +204,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "thumbv8m.main-none-eabihf", "toolchain": "llvm 23.1.3" @@ -190,6 +213,7 @@ "default": false, "note": "wasm, static, cross", "pin": "emsdk@6.0.9", + "platform": null, "status": "available", "target": "wasm32-emscripten", "toolchain": "emsdk 6.0.9" @@ -198,6 +222,7 @@ "default": false, "note": "cross", "pin": "android-ndk@30.0.16248370", + "platform": null, "status": "available", "target": "x86_64-linux-android", "toolchain": "android-ndk 30.0.16248370" @@ -206,6 +231,7 @@ "default": false, "note": "bare, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "available", "target": "x86_64-none-elf", "toolchain": "llvm 23.1.3" @@ -214,6 +240,7 @@ "default": false, "note": "ok, static, cross", "pin": "llvm@23.1.3", + "platform": "mcpplibs.openkal-platform@0.17.2", "status": "available", "target": "x86_64-openkal", "toolchain": "llvm 23.1.3" @@ -222,6 +249,7 @@ "default": false, "note": "PE, static, cross", "pin": "llvm@23.1.3", + "platform": null, "status": "via dependency graph", "target": "x86_64-windows-musl", "toolchain": "llvm 23.1.3" @@ -230,6 +258,7 @@ "default": false, "note": "static, cross", "pin": "", + "platform": null, "status": "planned", "target": "riscv64-linux-musl", "toolchain": "—" @@ -238,6 +267,7 @@ "default": false, "note": "cross", "pin": "", + "platform": null, "status": "planned", "target": "x86_64-macos", "toolchain": "—" @@ -278,7 +308,7 @@ "max": 1, "min": 1 }, - "version": "2026.10.26.2" + "version": "2026.10.27.1" }, "schemaVersion": 1 } diff --git a/protocol/fixtures/version.txt b/protocol/fixtures/version.txt index 9b0c5c9..851c895 100644 --- a/protocol/fixtures/version.txt +++ b/protocol/fixtures/version.txt @@ -1 +1 @@ -mcpp 2026.10.26.2 +mcpp 2026.10.27.1 diff --git a/protocol/mcpp-contract.schema.json b/protocol/mcpp-contract.schema.json index 5e32232..f83f435 100644 --- a/protocol/mcpp-contract.schema.json +++ b/protocol/mcpp-contract.schema.json @@ -52,7 +52,9 @@ "fingerprint": { "type": "string" }, "outputDir": { "type": "string" }, "profile": { "type": "string" }, - "triple": { "type": "string" } + "triple": { "type": "string" }, + "platform": { "$ref": "#/$defs/platform" }, + "hostPlatform": { "$ref": "#/$defs/platform" } } }, "platformField": { @@ -73,7 +75,10 @@ "type": "object", "required": ["argv", "cwd", "env"], "properties": { - "argv": { "type": "array", "minItems": 1, "items": { "type": "string" } }, + "argv": { + "description": "The command mcpp run gives the program; empty when `via` names what starts it (a target's runner, `run_under`), which `mcpp run --print-launch` resolves.", + "type": "array", "items": { "type": "string" } + }, "cwd": { "type": "string" }, "env": { "type": "object", "additionalProperties": { "type": "string" } }, "program": { "type": "string" }, @@ -237,7 +242,10 @@ "status": { "type": "string" }, "default": { "type": "boolean" }, "note": { "type": "string" }, - "platform": { "$ref": "#/$defs/platform" } + "platform": { + "description": "The platform the target table selects for the row, as a package spec (`mcpplibs.openkal-platform@0.17.2`); null for a row with none (mcpp SPEC-013).", + "type": ["string", "null"] + } } }, "toolchainListEnvelope": { diff --git a/src/bin/dev.cpp b/src/bin/dev.cpp index e57f067..3eb373a 100644 --- a/src/bin/dev.cpp +++ b/src/bin/dev.cpp @@ -156,7 +156,7 @@ int capture(std::span<const std::string> args) { std::string target; if (!doc.is_discarded() && doc.contains("data") && doc["data"].contains("targets")) for (const auto& t : doc["data"]["targets"]) - if (t.contains("platform") && t["platform"].is_object() && !t["platform"].value("name", "").empty()) { + if (t.contains("platform") && t["platform"].is_string() && !t["platform"].get<std::string>().empty()) { target = t.value("target", ""); break; } diff --git a/src/views.cppm b/src/views.cppm index e45d534..73f7f50 100644 --- a/src/views.cppm +++ b/src/views.cppm @@ -366,6 +366,17 @@ Json project_summary(const Json& envelope, const Json& lastResult) { return out; } +// A platform as the target table names it (`mcpp toolchain list`: `[ns.]name@version`), as the +// object a plan names one with: its name, version and where the choice came from. +Json platform_of_spec(const Json& spec) { + if (!spec.is_string()) return spec.is_object() ? spec : Json(nullptr); + const auto text = spec.get<std::string>(); + const auto at = text.rfind('@'); + return Json{{"name", at == std::string::npos ? text : text.substr(0, at)}, + {"version", at == std::string::npos ? Json(nullptr) : Json(text.substr(at + 1))}, + {"source", "target table"}}; +} + std::string platform_text(const Json& p) { if (!p.is_object()) return {}; const auto name = p.value("name", ""); @@ -394,7 +405,7 @@ Json targets(const Json& envelope, std::string_view selected) { if (fresh) order.push_back(target); auto& row = it->second; // mcpp reports the platform per row of the target table; every row of one target names the same. - if (row["platform"].is_null() && t.contains("platform") && t["platform"].is_object()) row["platform"] = t["platform"]; + if (row["platform"].is_null() && t.contains("platform")) row["platform"] = platform_of_spec(t["platform"]); auto tc = t.value("toolchain", ""); const auto sp = tc.find(' '); if (sp != std::string::npos) tc[sp] = '@'; @@ -444,9 +455,15 @@ Json stream_record(const Json& r) { const auto event = r.value("event", ""); if (r.value("kind", "") == "mcpp.event") { if (event == "plan") { - Json out{{"type", "plan"}, {"configuration", r.contains("configuration") ? r["configuration"] : Json(nullptr)}, - {"platform", r.contains("platform") ? r["platform"] : Json(nullptr)}, - {"hostPlatform", r.contains("hostPlatform") ? r["hostPlatform"] : Json(nullptr)}}; + // The platforms are the configuration's (mcpp's plan event: `configuration.platform`, + // `configuration.hostPlatform`). + const Json cfg = r.contains("configuration") ? r["configuration"] : Json(nullptr); + auto field = [&](const char* key) { + if (cfg.is_object() && cfg.contains(key)) return cfg[key]; + return r.contains(key) ? r[key] : Json(nullptr); + }; + Json out{{"type", "plan"}, {"configuration", cfg}, + {"platform", field("platform")}, {"hostPlatform", field("hostPlatform")}}; out["platformText"] = platform_text(out["platform"]); out["hostPlatformText"] = platform_text(out["hostPlatform"]); return out; diff --git a/tests/test_views.cpp b/tests/test_views.cpp index e25d511..2f66a9e 100644 --- a/tests/test_views.cpp +++ b/tests/test_views.cpp @@ -72,20 +72,21 @@ int main() { CHECK(r["platform"].is_null() == r["platformText"].get<std::string>().empty()); } CHECK(selected == 1); - Json platform{{"name", "openkal-platform"}, {"version", "0.17.1"}, {"source", "built-in"}}; - platform["fields"]["runner"] = Json{{"value", "okrun"}, {"source", "platform"}}; - list["data"]["targets"].push_back(Json{{"target", "x86_64-openkal"}, {"toolchain", "llvm 23.1.3"}, {"pin", "llvm@23.1.3"}, - {"status", "installed"}, {"default", false}, {"note", "ok"}, {"platform", platform}}); - list["data"]["hostPlatform"] = Json{{"name", ""}, {"version", nullptr}, {"source", "built-in"}}; - auto withPlatform = views::targets(list, "x86_64-openkal"); + // A row names its platform as the target table does, a package spec (mcpp SPEC-013); the view + // renders it as a plan's platform object. bool found = false; - for (const auto& r : withPlatform["rows"]) + for (const auto& r : t["rows"]) if (r["target"] == "x86_64-openkal") { found = true; - CHECK(r["selected"] == true); - CHECK(r["platformText"] == "openkal-platform 0.17.1 (built-in)"); + CHECK(r["platform"]["name"] == "mcpplibs.openkal-platform"); + CHECK(r["platformText"].get<std::string>().starts_with("mcpplibs.openkal-platform 0.17")); + CHECK(r["platformText"].get<std::string>().ends_with("(target table)")); } CHECK(found); + list["data"]["hostPlatform"] = Json{{"name", ""}, {"version", nullptr}, {"source", "built-in"}}; + auto withPlatform = views::targets(list, "x86_64-openkal"); + for (const auto& r : withPlatform["rows"]) + if (r["target"] == "x86_64-openkal") CHECK(r["selected"] == true); CHECK(withPlatform["hostPlatformText"] == "host conventions (built-in)"); // Stream records: each line of a build and of a test, normalised. From 5ed7154b53a3f7ce613bfa673edaa0f37a3c182f Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 10:06:38 +0900 Subject: [PATCH 19/30] The backend is one ok-image bundle with every system's okrun: each system packs its universal self-contained package, `mcpp pack --merge` joins them, and the editor packages carry the bundle and the joined okrun; the program-per-system form is gone; a host-platform row; CI builds mcpp from MCPP_SOURCE_REF until it is released Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/actions/setup-mcpp/action.yml | 53 ++++- .github/scripts/check-package.sh | 41 ++-- .github/versions.env | 6 +- .github/workflows/ci.yml | 187 ++++++++++++------ .github/workflows/release.yml | 14 +- CHANGELOG.md | 9 +- README.md | 7 +- README.zh-CN.md | 6 +- docs/architecture.md | 18 +- jetbrains/README.md | 7 +- jetbrains/build.gradle.kts | 5 +- .../mcppcommunity/mcppclion/backend/Locate.kt | 13 +- .../mcppcommunity/mcppclion/BackendTest.kt | 11 +- src/bin/dev.cpp | 4 - vscode/README.md | 5 +- vscode/src/backend/locate.ts | 13 +- vscode/test/e2e/runTest.ts | 3 +- vscode/test/unit/locate.test.ts | 20 +- 18 files changed, 252 insertions(+), 170 deletions(-) diff --git a/.github/actions/setup-mcpp/action.yml b/.github/actions/setup-mcpp/action.yml index ed417d9..f6bd7bb 100644 --- a/.github/actions/setup-mcpp/action.yml +++ b/.github/actions/setup-mcpp/action.yml @@ -1,5 +1,5 @@ name: Set up mcpp -description: Install xlings, the pinned mcpp and (for macOS and Windows targets) the pinned LLVM, with the package store cached. +description: Install xlings, the pinned mcpp (built from MCPP_SOURCE_REF when it is set) and (for macOS and Windows targets) the pinned LLVM, with the package store cached. inputs: llvm: description: Install LLVM and make it mcpp's default toolchain. @@ -58,3 +58,54 @@ runs: sleep 30 done mcpp toolchain default "llvm@$LLVM_VERSION" + # MCPP_SOURCE_REF: mcpp built from that ref by the release installed above, before the ref is + # released; the program is kept per commit and system, and put first on PATH. + - name: Resolve MCPP_SOURCE_REF + id: source + if: env.MCPP_SOURCE_REF != '' + shell: bash + run: | + set -euo pipefail + sha="$(git ls-remote https://github.com/mcpp-community/mcpp.git "refs/heads/$MCPP_SOURCE_REF" "refs/tags/$MCPP_SOURCE_REF" | head -1 | cut -f1)" + [ -n "$sha" ] || { echo "::error::mcpp-community/mcpp has no branch or tag $MCPP_SOURCE_REF"; exit 1; } + echo "sha=$sha" >> "$GITHUB_OUTPUT" + - name: Restore mcpp built from ${{ env.MCPP_SOURCE_REF }} + id: kept + if: env.MCPP_SOURCE_REF != '' + uses: actions/cache/restore@v5 + with: + path: ~/.mcpp-source/bin + key: mcpp-source-${{ runner.os }}-${{ runner.arch }}-${{ steps.source.outputs.sha }} + - name: mcpp from ${{ env.MCPP_SOURCE_REF }} + id: built + if: env.MCPP_SOURCE_REF != '' + shell: bash + env: + SHA: ${{ steps.source.outputs.sha }} + run: | + set -euo pipefail + case "$RUNNER_OS" in Windows) exe=mcpp.exe ;; *) exe=mcpp ;; esac + bin="$HOME/.mcpp-source/bin" + # A kept program that does not start (its toolchain's run-time is not in this store) is built again. + if ! "$bin/$exe" --version > /dev/null 2>&1; then + src="$RUNNER_TEMP/mcpp-source" + rm -rf "$src" + git init -q "$src" + git -C "$src" fetch -q --depth 1 https://github.com/mcpp-community/mcpp.git "$SHA" + git -C "$src" checkout -q FETCH_HEAD + (cd "$src" && mcpp build) + built="$(find "$src/target" -type f -name "$exe" -path '*/bin/*' ! -path '*/dist/*' | head -1)" + [ -n "$built" ] || { echo "::error::building mcpp at $MCPP_SOURCE_REF left no $exe"; exit 1; } + mkdir -p "$bin" + cp "$built" "$bin/$exe" + echo "fresh=true" >> "$GITHUB_OUTPUT" + fi + "$bin/$exe" --version + case "$RUNNER_OS" in Windows) cygpath -w "$bin" ;; *) echo "$bin" ;; esac >> "$GITHUB_PATH" + # Kept as soon as it is built, so a job that fails later does not build it again. + - name: Keep mcpp built from ${{ env.MCPP_SOURCE_REF }} + if: env.MCPP_SOURCE_REF != '' && steps.built.outputs.fresh == 'true' && steps.kept.outputs.cache-hit != 'true' + uses: actions/cache/save@v5 + with: + path: ~/.mcpp-source/bin + key: ${{ steps.kept.outputs.cache-primary-key }} diff --git a/.github/scripts/check-package.sh b/.github/scripts/check-package.sh index 0f6abef..c9e8752 100755 --- a/.github/scripts/check-package.sh +++ b/.github/scripts/check-package.sh @@ -2,10 +2,9 @@ # check-package.sh <package> <root inside the archive> # # What an editor package carries of the backend, checked on the system this runs on (CI runs it on -# every system): with the ok-image bundle (mcpp design 2026-10-28 part 2 §15), exactly one -# backend/mcpp-ide.okb, an okrun for every system and architecture, and the one for this system -# starting the bundle; until the bundle is built, a program for every system, and the one for this -# system answering. +# every system): the ok-image bundle (mcpp design 2026-10-28 part 2 §15), exactly one +# backend/mcpp-ide.okb; an okrun for every system and architecture CI packs; and the one for this +# system starting the bundle. set -euo pipefail package="$1" prefix="$2" dir="$(mktemp -d)" @@ -13,8 +12,8 @@ trap 'rm -rf "$dir"' EXIT unzip -q "$package" -d "$dir" root="$dir/$prefix" -case "$(uname -s)" in Linux) os=linux vs=linux ;; Darwin) os=macos vs=darwin ;; *) os=windows vs=win32 ;; esac -case "$(uname -m)" in x86_64|amd64|AMD64) arch=x86_64 va=x64 ;; aarch64|arm64|ARM64) arch=aarch64 va=arm64 ;; *) arch="$(uname -m)" va="$arch" ;; esac +case "$(uname -s)" in Linux) os=linux ;; Darwin) os=macos ;; *) os=windows ;; esac +case "$(uname -m)" in x86_64|amd64|AMD64) arch=x86_64 ;; aarch64|arm64|ARM64) arch=aarch64 ;; *) arch="$(uname -m)" ;; esac exe=""; [ "$os" = windows ] && exe=".exe" answers() { # <argv...>: the backend says who it is @@ -25,25 +24,13 @@ answers() { # <argv...>: the backend says who it is } okbs="$(find "$root" -name '*.okb' | wc -l | tr -d ' ')" -if [ "$okbs" != 0 ]; then - [ "$okbs" = 1 ] || { echo "::error::$package carries $okbs ok-image bundles; one is expected"; exit 1; } - [ -f "$root/backend/mcpp-ide.okb" ] || { echo "::error::the bundle is not backend/mcpp-ide.okb"; exit 1; } - for want in linux-x86_64 linux-aarch64 macos-aarch64 windows-x86_64; do - ls "$root/backend/okrun/$want/"okrun* > /dev/null 2>&1 || { echo "::error::$package carries no okrun for $want"; exit 1; } - done - okrun="$root/backend/okrun/$os-$arch/okrun$exe" - chmod +x "$okrun" 2>/dev/null || true - answers "$okrun" "$root/backend/mcpp-ide.okb" - echo "$package: one bundle; okrun for $os-$arch starts it" - exit 0 -fi - -[ -d "$root/backend" ] && { echo "::error::$package has backend/ but no bundle"; exit 1; } -echo "::notice::$package carries no ok-image bundle yet (mcpp's platforms and openkal 0.17.2); checking its per-system programs" -for want in linux-x64/mcpp-ide linux-arm64/mcpp-ide darwin-arm64/mcpp-ide win32-x64/mcpp-ide.exe; do - [ -f "$root/bin/$want" ] || { echo "::error::$package carries no bin/$want"; exit 1; } +[ "$okbs" = 1 ] || { echo "::error::$package carries $okbs ok-image bundles; one is expected"; exit 1; } +[ -f "$root/backend/mcpp-ide.okb" ] || { echo "::error::the bundle is not backend/mcpp-ide.okb"; exit 1; } +for want in linux-x86_64 linux-aarch64 macos-aarch64 windows-x86_64; do + ls "$root/backend/okrun/$want/"okrun* > /dev/null 2>&1 || { echo "::error::$package carries no okrun for $want"; exit 1; } done -program="$root/bin/$vs-$va/mcpp-ide$exe" -chmod +x "$program" 2>/dev/null || true -answers "$program" -echo "$package: a program for every system; the one for $vs-$va answers" +[ -d "$root/bin" ] && { echo "::error::$package carries bin/ beside the bundle"; exit 1; } +okrun="$root/backend/okrun/$os-$arch/okrun$exe" +chmod +x "$okrun" 2>/dev/null || true +answers "$okrun" "$root/backend/mcpp-ide.okb" +echo "$package: one bundle; okrun for $os-$arch starts it" diff --git a/.github/versions.env b/.github/versions.env index da8fcbd..3a45f79 100644 --- a/.github/versions.env +++ b/.github/versions.env @@ -1,6 +1,10 @@ # The versions CI builds and tests with, in one file; .github/actions/setup-mcpp exports them. -# The mcpp whose control contract the fixtures were captured from (protocol/fixtures/version.txt). +# The released mcpp CI installs; with MCPP_SOURCE_REF, the one that builds mcpp from that ref. MCPP_VERSION=2026.10.26.2 +# Until mcpp 2026.10.27.1 is released: the ref of mcpp-community/mcpp CI builds and uses, whose control +# contract the fixtures were captured from (protocol/fixtures/version.txt) and whose platforms +# (openkal-platform 0.17.2) the backend's ok images are built on. Empty: the release above is used. +MCPP_SOURCE_REF=release/2026.10.27.1 # The LLVM the backend builds with on macOS and Windows (the targets mcpp reaches there with it). LLVM_VERSION=23.1.3 # The xlings mcpp 2026.10.26.2 bundles, which reads the current index. diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 69c881e..1487862 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,26 +17,24 @@ env: jobs: # The backend on each system the editors run on: build every program (the backend, the mock mcpp, # the dev tool), run the tests -- the protocol against its schema and the fixtures against mcpp's - # contract among them -- check the translations, then build the release program the editor - # packages carry, laid out bin/<platform>/. - # - # When mcpp's platforms ship (mcpp design 2026-10-28), the release program becomes one ok image per - # architecture (`--target <arch>-openkal`) made into a program of each system by - # `mcpp pack --mode self-contained`; only the last two steps change, not the layout they upload. + # contract among them -- and check the translations. A `pack` leg then packs the backend as the + # editor packages carry it (mcpp design 2026-10-28 part 2 §15): its universal self-contained + # package (`<arch>-openkal`: the x86_64 and aarch64 images, okrun for this system's architectures), + # and on linux-x64 the ok-image bundle. The `host-platform` row builds and tests with the build + # programs (build.mcpp, the spec/ generators) as ok images run by okrun. backend: - name: backend (${{ matrix.platform }}) + name: backend (${{ matrix.platform }}${{ matrix.host-platform && format(', host platform {0}', matrix.host-platform) || '' }}) runs-on: ${{ matrix.os }} - timeout-minutes: 60 + timeout-minutes: 75 strategy: fail-fast: false matrix: - # `releases`: the release programs a leg builds, as `<platform>=<target>` (empty target: this - # system). The arm64 Linux program is cross-built on x86_64, where musl-gcc's cross payload is. include: - - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', releases: 'linux-x64=x86_64-linux-musl linux-arm64=aarch64-linux-musl' } - - { os: ubuntu-24.04-arm, platform: linux-arm64, llvm: 'false', releases: '' } - - { os: macos-14, platform: darwin-arm64, llvm: 'true', releases: 'darwin-arm64=' } - - { os: windows-2022, platform: win32-x64, llvm: 'true', releases: 'win32-x64=' } + - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: 'package okb' } + - { os: ubuntu-24.04-arm, platform: linux-arm64, llvm: 'false', pack: '' } + - { os: macos-14, platform: darwin-arm64, llvm: 'true', pack: 'package' } + - { os: windows-2022, platform: win32-x64, llvm: 'true', pack: 'package' } + - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: '', host-platform: 'openkal-platform@0.17.2' } defaults: run: shell: bash @@ -45,43 +43,97 @@ jobs: - uses: ./.github/actions/setup-mcpp with: llvm: ${{ matrix.llvm }} + - name: The host graph's platform + if: matrix.host-platform + run: echo "MCPP_HOST_PLATFORM=${{ matrix.host-platform }}" >> "$GITHUB_ENV" - name: Build run: mcpp build - name: Test run: mcpp test - name: Every string has its translation run: mcpp run mcpp-ide-dev -- check-i18n - - name: Release programs - if: matrix.releases != '' + - name: The backend's packages + if: matrix.pack != '' run: | set -euo pipefail - for entry in ${{ matrix.releases }}; do - platform="${entry%%=*}" target="${entry#*=}" - case "$platform" in win32-*) exe=mcpp-ide.exe ;; *) exe=mcpp-ide ;; esac - if [ -n "$target" ]; then - mcpp build --release --target "$target" - built="$(ls -t target/"$target"/*/bin/$exe | head -1)" - else - mcpp build --release - built="$(ls -t target/*/*/bin/$exe | head -1)" - fi - mkdir -p "out/$platform" - cp "$built" "out/$platform/" - file "out/$platform/$exe" 2>/dev/null || true - done - case "${{ matrix.platform }}" in win32-*) out/win32-x64/mcpp-ide.exe --version ;; *) "out/${{ matrix.platform }}/mcpp-ide" --version ;; esac + version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" + case "$(uname -m)" in x86_64|amd64|AMD64) arch=x86_64 ;; *) arch=aarch64 ;; esac + case "$RUNNER_OS" in Linux) system=linux ;; macOS) system=macos ;; *) system=windows ;; esac + package="mcpp-ide-$version-openkal" + mkdir -p out + mcpp pack mcpp-ide --target "$arch-openkal" --mode self-contained --pkg-format dir + cp -R "target/dist/$package" out/ + ls -R "out/$package/libexec" + if [ "$system" = windows ]; then + (cd "out/$package/bin" && cmd //c "mcpp-ide.cmd --version") + else + "out/$package/bin/mcpp-ide" --version + fi + case " ${{ matrix.pack }} " in *" okb "*) + mcpp pack mcpp-ide --target "$arch-openkal" --pkg-format okb + cp "target/dist/mcpp-ide-$version.okb" out/mcpp-ide.okb + "out/$package/libexec/okrun/$system-$arch/okrun" out/mcpp-ide.okb --version + ls -l out/mcpp-ide.okb + ;; + esac - uses: actions/upload-artifact@v5 - if: matrix.releases != '' + if: matrix.pack != '' with: name: backend-${{ matrix.platform }} path: out + # The packages of every system made one (`mcpp pack --merge`): the universal self-contained package + # (both images, okrun for every system a leg packed), and what the editor packages carry of it -- + # the bundle and the okrun of each system and architecture. + backend-package: + name: backend package + needs: backend + runs-on: ubuntu-24.04 + timeout-minutes: 30 + defaults: + run: + shell: bash + steps: + - uses: actions/checkout@v5 + - uses: ./.github/actions/setup-mcpp + - uses: actions/download-artifact@v5 + with: + pattern: backend-* + path: backends + - name: One package for every system + run: | + set -euo pipefail + version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" + package="mcpp-ide-$version-openkal" + # An artifact does not keep the mode bits. + chmod +x backends/*/"$package"/bin/mcpp-ide backends/*/"$package"/libexec/okrun/*/okrun* + mkdir -p merged backend + merge=() + for p in backends/*/"$package"; do merge+=(--merge "$p"); done + mcpp pack "${merge[@]}" --pkg-format dir -o "$PWD/merged/$package" + mcpp pack "${merge[@]}" -o "$PWD/backend/$package.tar.gz" + cp backends/backend-linux-x64/mcpp-ide.okb backend/mcpp-ide.okb + cp -R "merged/$package/libexec/okrun" backend/okrun + python3 - "merged/$package/mcpp-package.json" <<'PY' + import json, sys + d = json.load(open(sys.argv[1])) + print("legs", d["legs"], "systems", d["systems"]) + want = {"linux-x86_64", "linux-aarch64", "macos-aarch64", "windows-x86_64"} + assert want <= set(d["systems"]), d["systems"] + PY + backend/okrun/linux-x86_64/okrun backend/mcpp-ide.okb --version + ls -lR backend + - uses: actions/upload-artifact@v5 + with: + name: backend + path: backend + # The VS Code extension: unit tests (the wire, the mappings) and the shared panels in a DOM, both # against the backend built here; the extension in a real VS Code (the oldest it supports) over the - # mock mcpp; then the package carrying every system's backend, and its file list. + # mock mcpp, with that backend and with the bundle it carries; then the package, and its file list. vscode: name: VS Code extension - needs: backend + needs: backend-package runs-on: ubuntu-24.04 timeout-minutes: 45 defaults: @@ -97,13 +149,16 @@ jobs: cache-dependency-path: vscode/package-lock.json - uses: actions/download-artifact@v5 with: - pattern: backend-* - path: backends - merge-multiple: true + name: backend + path: backend - name: Build the backend and its test programs run: | - chmod +x backends/*/mcpp-ide* + chmod +x backend/okrun/*/okrun* mcpp build + { + echo "MCPP_IDE_OKB=$GITHUB_WORKSPACE/backend/mcpp-ide.okb" + echo "MCPP_IDE_OKRUN=$GITHUB_WORKSPACE/backend/okrun" + } >> "$GITHUB_ENV" - name: Install working-directory: vscode run: npm ci @@ -115,25 +170,27 @@ jobs: run: npm run check:webui - name: The extension in VS Code ${{ env.VSCODE_VERSION }} working-directory: vscode - run: MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" xvfb-run -a npm run test:e2e + run: xvfb-run -a npm run test:e2e - name: Package working-directory: vscode run: | - MCPP_IDE_BACKENDS="$GITHUB_WORKSPACE/backends" npm run package + npm run package (cd dist/extension && npx vsce ls --no-dependencies) | tee files.txt - for p in linux-x64 linux-arm64 darwin-arm64; do grep -qx "bin/$p/mcpp-ide" files.txt; done - grep -qx "bin/win32-x64/mcpp-ide.exe" files.txt + grep -qx "backend/mcpp-ide.okb" files.txt + for p in linux-x86_64/okrun linux-aarch64/okrun macos-aarch64/okrun windows-x86_64/okrun.exe; do grep -qx "backend/okrun/$p" files.txt; done + [ "$(grep -c '\.okb$' files.txt)" = 1 ] + ls -l dist/*.vsix - uses: actions/upload-artifact@v5 with: name: mcpp-vscode-vsix path: vscode/dist/*.vsix - # The CLion plugin: its tests (the wire and a session over the mock mcpp), the archive carrying - # every system's backend, and the Plugin Verifier against the oldest CLion it claims (2025.2) and - # the one it is built on. + # The CLion plugin: its tests (the wire and a session over the mock mcpp), the archive carrying the + # bundle and every system's okrun, and the Plugin Verifier against the oldest CLion it claims + # (2025.2) and the one it is built on. jetbrains: name: CLion plugin - needs: backend + needs: backend-package runs-on: ubuntu-24.04 timeout-minutes: 90 defaults: @@ -150,12 +207,11 @@ jobs: key: gradle-clion-${{ hashFiles('jetbrains/gradle.properties', 'jetbrains/build.gradle.kts', 'jetbrains/settings.gradle.kts') }} - uses: actions/download-artifact@v5 with: - pattern: backend-* - path: backends - merge-multiple: true + name: backend + path: backend - name: Build the backend and its test programs run: | - chmod +x backends/*/mcpp-ide* + chmod +x backend/okrun/*/okrun* mcpp build # Every Gradle run of this job packages the same plugin: the variables hold for all of them. bin="$(cd "$(dirname "$(ls -t target/*/*/bin/mcpp-ide | head -1)")" && pwd)" @@ -163,7 +219,8 @@ jobs: echo "MCPP_IDE_DEV=$bin/mcpp-ide-dev" echo "MCPP_IDE_BACKEND=$bin/mcpp-ide" echo "MCPP_IDE_MOCK_MCPP=$bin/mcpp-ide-mock-mcpp" - echo "MCPP_IDE_BACKENDS=$GITHUB_WORKSPACE/backends" + echo "MCPP_IDE_OKB=$GITHUB_WORKSPACE/backend/mcpp-ide.okb" + echo "MCPP_IDE_OKRUN=$GITHUB_WORKSPACE/backend/okrun" } >> "$GITHUB_ENV" - name: Test and package working-directory: jetbrains @@ -171,18 +228,22 @@ jobs: - name: Plugin Verifier working-directory: jetbrains run: gradle --no-daemon verifyPlugin - - name: The archive carries every system's backend + - name: The archive carries the bundle and every system's okrun working-directory: jetbrains run: | unzip -l build/distributions/mcpp-clion-*.zip | tee files.txt - for p in linux-x64/mcpp-ide linux-arm64/mcpp-ide darwin-arm64/mcpp-ide win32-x64/mcpp-ide.exe; do grep -q "mcpp-clion/bin/$p" files.txt; done + grep -q "mcpp-clion/backend/mcpp-ide.okb" files.txt + for p in linux-x86_64/okrun linux-aarch64/okrun macos-aarch64/okrun windows-x86_64/okrun.exe; do grep -q "mcpp-clion/backend/okrun/$p" files.txt; done + [ "$(grep -c '\.okb$' files.txt)" = 1 ] + ls -l build/distributions/*.zip - uses: actions/upload-artifact@v5 with: name: mcpp-clion-zip path: jetbrains/build/distributions/*.zip - # Both packages, opened on every system they serve: what each carries of the backend for that - # system starts (scripts/check-package.sh -- the ok-image bundle and its okrun once they are built). + # The packages, opened on every system they serve: the one bundle each editor package carries, + # started by the okrun it carries for that system (scripts/check-package.sh), and the backend's own + # universal package started by its launcher. packages: name: packages on ${{ matrix.os }} needs: [vscode, jetbrains] @@ -202,7 +263,23 @@ jobs: pattern: mcpp-* path: packages merge-multiple: true + - uses: actions/download-artifact@v5 + with: + name: backend + path: backend - name: The VS Code extension run: .github/scripts/check-package.sh packages/mcpp-vscode-*.vsix extension - name: The CLion plugin run: .github/scripts/check-package.sh packages/mcpp-clion-*.zip mcpp-clion + - name: The backend's universal package + run: | + set -euo pipefail + dir="$(mktemp -d)" + tar -xzf backend/mcpp-ide-*-openkal.tar.gz -C "$dir" + root="$(echo "$dir"/mcpp-ide-*-openkal)" + if [ "$RUNNER_OS" = Windows ]; then + (cd "$root/bin" && cmd //c "mcpp-ide.cmd --version") | tee said.txt + else + "$root/bin/mcpp-ide" --version | tee said.txt + fi + grep -q '^mcpp-ide ' said.txt diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 4f0fdc4..a436781 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,8 +1,9 @@ name: Release -# A release: CI on the commit (which builds every system's backend and both editor packages carrying -# them), then a GitHub release with the packages, the backends and their checksums. The two -# Marketplaces are uploaded to by the maintainer, from those assets. +# A release: CI on the commit (which builds the backend's ok-image bundle, its universal package with +# every system's okrun, and both editor packages carrying the bundle), then a GitHub release with the +# editor packages, the bundle, the universal package and their checksums. The two Marketplaces are +# uploaded to by the maintainer, from those assets. on: workflow_dispatch: @@ -34,10 +35,7 @@ jobs: version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" mkdir -p dist cp artifacts/mcpp-vscode-vsix/*.vsix artifacts/mcpp-clion-zip/*.zip dist/ - for d in artifacts/backend-*; do - platform="${d#artifacts/backend-}" - chmod +x "$d/$platform"/* || true - tar -czf "dist/mcpp-ide-${version}-${platform}.tar.gz" -C "$d/$platform" . - done + cp artifacts/backend/mcpp-ide.okb "dist/mcpp-ide-${version}.okb" + cp "artifacts/backend/mcpp-ide-${version}-openkal.tar.gz" dist/ (cd dist && sha256sum * > SHA256SUMS && cat SHA256SUMS) gh release create "v${version}" dist/* --target "$GITHUB_SHA" --title "mcpp-ide ${version}" --notes-file CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md index 55df7a1..2d8003c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,13 +8,14 @@ The first release of mcpp-ide: one backend for mcpp's editor integrations, the V - Backend (`mcpp-ide serve`): sessions, watching, jobs, view models, cleanup plans, settings, the command table, runtime strings, self-check; handshakes with mcpp and mcppls; targets with their platforms. -- Protocol and contract schemas, held against mcpp 2026.10.26.2's real output. +- Protocol and contract schemas, held against mcpp 2026.10.27.1's real output (target rows naming + their platform, a plan's platform and host platform, a wrapped program's launch). - Shared panels: project, targets and platforms, libraries, dependency and module graphs, cache, pack, settings. - VS Code: tasks, Testing view, debug configurations, Problems from mcpp, mcpp.toml editing help. - CLion: run configurations with a PTY console, test tree, CLion's debugger, console links, the mcpp tool window; depends on the mcppls CLion plugin. -- One package per editor for every system: the backend as an ok-image bundle with okrun per system - (or a program per system until the bundle is built); CI starts it from both packages on Linux - x64/arm64, macOS and Windows. +- One package per editor for every system: the backend as one ok-image bundle (x86_64 and aarch64 + images on openkal-platform 0.17.2) with okrun for Linux x86_64/aarch64, macOS arm64 and Windows + x64; CI starts it from both packages on each of those systems. - `mcpp pack`'s package format is passed as `--pkg-format` where mcpp offers it (`--format` before). diff --git a/README.md b/README.md index fd429da..31bccfd 100644 --- a/README.md +++ b/README.md @@ -54,12 +54,11 @@ on my mcpp project. | VS Code | the Marketplace (`mcpp-community.mcpp-vscode`), or `mcpp-vscode-<version>.vsix` | search *mcpp*, or `code --install-extension mcpp-vscode-<version>.vsix` | | VS Code-compatible editors | Open VSX, or the `.vsix` | install the `.vsix` from the extensions view | | CLion 2025.2+ | JetBrains Marketplace (`mcpp-clion`), or `mcpp-clion-<version>.zip` | Settings → Plugins → Install Plugin from Disk; the mcppls CLion plugin first | -| Agents, other clients | `mcpp-ide-<version>-<platform>.tar.gz`, or `xlings install mcpp-ide` | run `mcpp-ide serve` | +| Agents, other clients | `mcpp-ide-<version>-openkal.tar.gz` (both images; okrun for Linux x64/arm64, macOS arm64, Windows x64), `mcpp-ide-<version>.okb` with okrun, or `xlings install mcpp-ide` | run `bin/mcpp-ide serve` (`bin\mcpp-ide.cmd` on Windows), or `okrun mcpp-ide-<version>.okb serve` | Each editor package serves every system: it carries the backend as one ok-image bundle -(`backend/mcpp-ide.okb`) and okrun for each system and architecture (mcpp's platforms, openkal -0.17.2); until that bundle is built, it carries a program for each of Linux x64/arm64, macOS arm64 -and Windows x64. +(`backend/mcpp-ide.okb`, the x86_64 and aarch64 images on openkal-platform 0.17.2) and okrun for +Linux x64/arm64, macOS arm64 and Windows x64. ### From source diff --git a/README.zh-CN.md b/README.zh-CN.md index 8338ef5..d79a58e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -49,10 +49,10 @@ C++ 文件的语言功能来自 [mcppls](https://github.com/Sunrisepeak/mcpp-lan | VS Code | Marketplace(`mcpp-community.mcpp-vscode`),或 `mcpp-vscode-<version>.vsix` | 搜索 *mcpp*,或 `code --install-extension mcpp-vscode-<version>.vsix` | | 兼容 VS Code 的编辑器 | Open VSX,或 `.vsix` | 在扩展视图中安装 `.vsix` | | CLion 2025.2+ | JetBrains Marketplace(`mcpp-clion`),或 `mcpp-clion-<version>.zip` | Settings → Plugins → Install Plugin from Disk;先安装 mcppls CLion 插件 | -| Agent、其他客户端 | `mcpp-ide-<version>-<platform>.tar.gz`,或 `xlings install mcpp-ide` | 运行 `mcpp-ide serve` | +| Agent、其他客户端 | `mcpp-ide-<version>-openkal.tar.gz`(两个架构的映像;Linux x64/arm64、macOS arm64、Windows x64 的 okrun),携带 okrun 的 `mcpp-ide-<version>.okb`,或 `xlings install mcpp-ide` | 运行 `bin/mcpp-ide serve`(Windows 上为 `bin\mcpp-ide.cmd`),或 `okrun mcpp-ide-<version>.okb serve` | -每个编辑器包都服务全部系统:后端以一个 ok 映像包(`backend/mcpp-ide.okb`)加上各系统 × 架构的 okrun 携带 -(mcpp 的平台、openkal 0.17.2);在该映像包构建出来之前,包内携带 Linux x64/arm64、macOS arm64、Windows x64 各一份程序。 +每个编辑器包都服务全部系统:后端以一个 ok 映像包(`backend/mcpp-ide.okb`,openkal-platform 0.17.2 上的 +x86_64 与 aarch64 映像)加上 Linux x64/arm64、macOS arm64、Windows x64 的 okrun 携带。 ### 从源码构建 diff --git a/docs/architecture.md b/docs/architecture.md index 18fa675..64713bf 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -33,16 +33,20 @@ build through mcpp's result record, and an older or missing mcppls is reported w ## Distribution -The backend is one program for every editor; each editor package carries it for every system: +The backend is one program for every editor, and one file for every system: an ok image per +architecture (`mcpp build --target <arch>-openkal`, openkal-platform's toolchain and C library), +packed as one ok-image bundle (`mcpp pack mcpp-ide --target x86_64-openkal --pkg-format okb`). Each +editor package carries that bundle and the runner that starts it on each system: -| Form | Layout in the package | Started as | +| Layout in the package | Holds | Started as | |---|---|---| -| ok-image bundle (mcpp design 2026-10-28 part 2 §15) | `backend/mcpp-ide.okb`, `backend/okrun/<os>-<arch>/okrun[.exe]` | `okrun mcpp-ide.okb serve`: the okrun carried for this system, else okrun on PATH | -| a program per system, until the bundle is built | `bin/<platform>/mcpp-ide[.exe]` | `mcpp-ide serve` | +| `backend/mcpp-ide.okb` | the x86_64 and aarch64 images | | +| `backend/okrun/<os>-<arch>/okrun[.exe]` | okrun for `linux-x86_64`, `linux-aarch64`, `macos-aarch64`, `windows-x86_64`, from `mcpp pack --mode self-contained` on each system | `okrun mcpp-ide.okb serve`: the okrun carried for this system, else okrun on PATH | -Before either, a configured `mcpp.ide.backendPath` (a program or an `.okb`) is used; after them, an -installed `mcpp-ide` (xlings, whose command runs okrun on its bundle) or one on PATH. CI opens both -packages on every system and starts what they carry for it (`.github/scripts/check-package.sh`). +Before it, a configured `mcpp.ide.backendPath` (a program or an `.okb`) is used; after it, an +installed `mcpp-ide` (xlings, whose command runs okrun on its bundle) or one on PATH. CI builds the +bundle once, takes okrun from each system's self-contained package, opens both editor packages on +every system and starts what they carry for it (`.github/scripts/check-package.sh`). ## Generated declarations diff --git a/jetbrains/README.md b/jetbrains/README.md index c13321e..c1822d8 100644 --- a/jetbrains/README.md +++ b/jetbrains/README.md @@ -25,10 +25,9 @@ gradle verifyPlugin # CLion 2025.2 and the version in gradle.proper ``` What the archive carries of the backend: `MCPP_IDE_OKB` (the ok-image bundle, as -`backend/mcpp-ide.okb`) with `MCPP_IDE_OKRUN` (okrun laid out `<os>-<arch>/okrun[.exe]`), or, until -the bundle is built, `MCPP_IDE_BACKENDS` (a program per system laid out `<platform>/mcpp-ide[.exe]`: -`linux-x64`, `linux-arm64`, `darwin-arm64`, `win32-x64`). Without them the plugin finds the backend -through `mcpp.ide.backendPath`, xlings or PATH. +`backend/mcpp-ide.okb`) with `MCPP_IDE_OKRUN` (okrun laid out `<os>-<arch>/okrun[.exe]`); see +docs/architecture.md, Distribution. Without them the plugin finds the backend through +`mcpp.ide.backendPath`, xlings or PATH. ## Tests diff --git a/jetbrains/build.gradle.kts b/jetbrains/build.gradle.kts index 67c55e9..1c35268 100644 --- a/jetbrains/build.gradle.kts +++ b/jetbrains/build.gradle.kts @@ -90,16 +90,13 @@ tasks.processResources { dependsOn(generateDeclarations, copyWebui) } // What the plugin carries of the backend (mcpp design 2026-10-28 part 2 §15), as the VS Code // extension carries it: MCPP_IDE_OKB, the ok-image bundle (backend/mcpp-ide.okb, one for every -// system); MCPP_IDE_OKRUN, okrun per system and architecture (backend/okrun/<os>-<arch>/); and, -// until the bundle is built, MCPP_IDE_BACKENDS, a program per system (bin/<platform>/). +// system), and MCPP_IDE_OKRUN, okrun per system and architecture (backend/okrun/<os>-<arch>/). val okb = providers.environmentVariable("MCPP_IDE_OKB") val okrun = providers.environmentVariable("MCPP_IDE_OKRUN") -val backends = providers.environmentVariable("MCPP_IDE_BACKENDS") tasks.prepareSandbox { val plugin = intellijPlatform.projectName.get() if (okb.isPresent) from(okb.get()) { into("$plugin/backend"); rename { "mcpp-ide.okb" } } if (okrun.isPresent) from(okrun.get()) { into("$plugin/backend/okrun") } - if (backends.isPresent) from(backends.get()) { into("$plugin/bin") } } intellijPlatform { diff --git a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt index c5e865d..3b5c449 100644 --- a/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt +++ b/jetbrains/src/main/kotlin/io/github/mcppcommunity/mcppclion/backend/Locate.kt @@ -4,9 +4,7 @@ // 1. mcpp.ide.backendPath: a program, or an ok-image bundle (`*.okb`) run by okrun; // 2. the bundle the plugin carries, `backend/mcpp-ide.okb`, run by the okrun it carries for this // system (`backend/okrun/<os>-<arch>/okrun[.exe]`), else by okrun on PATH; -// 3. a program the plugin carries for this system (`bin/<platform>/mcpp-ide[.exe]`), the form -// packages take until the bundle is built; -// 4. the mcpp-ide xlings installed, then PATH. +// 3. the mcpp-ide xlings installed, then PATH. package io.github.mcppcommunity.mcppclion.backend import java.io.File @@ -29,13 +27,6 @@ object Locate { else -> arch.lowercase() } - /** "linux-x64", "darwin-arm64", "win32-x64": the bin/ directories, named as the VS Code extension names them. */ - fun platformDir(os: String = System.getProperty("os.name"), arch: String = System.getProperty("os.arch")): String { - val s = when (system(os)) { "windows" -> "win32"; "macos" -> "darwin"; else -> "linux" } - val m = when (machine(arch)) { "x86_64" -> "x64"; "aarch64" -> "arm64"; else -> machine(arch) } - return "$s-$m" - } - /** "linux-x86_64", "macos-aarch64", "windows-x86_64": mcpp's names, which the okrun directories use. */ fun okrunDir(os: String = System.getProperty("os.name"), arch: String = System.getProperty("os.arch")): String = "${system(os)}-${machine(arch)}" @@ -68,8 +59,6 @@ object Locate { pluginRoot?.let { root -> val bundle = File(root, "backend/mcpp-ide.okb") if (bundle.isFile) okrun()?.let { return Located(listOf(it.path, bundle.path), "bundle") } - val bundled = File(root, "bin/${platformDir(os, arch)}/${exe("mcpp-ide", onWin)}") - if (bundled.isFile) return Located(listOf(runnable(bundled).path), "bundled") } listOfNotNull(System.getenv("XLINGS_HOME")?.let { File(it, "subos/current/bin/${exe("mcpp-ide", onWin)}") }, File(home, ".xlings/subos/current/bin/${exe("mcpp-ide", onWin)}"), diff --git a/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt b/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt index 5d1acdd..f83f07f 100644 --- a/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt +++ b/jetbrains/src/test/kotlin/io/github/mcppcommunity/mcppclion/BackendTest.kt @@ -31,13 +31,6 @@ class BackendTest { assertEquals(listOf("""{"a":1}""", """{"b":"é"}"""), bodies) } - @Test - fun platformDirectories() { - assertEquals("linux-x64", Locate.platformDir("Linux", "amd64")) - assertEquals("darwin-arm64", Locate.platformDir("Mac OS X", "aarch64")) - assertEquals("win32-x64", Locate.platformDir("Windows 11", "x86_64")) - } - @Test fun theBundleRunsUnderTheOkrunCarriedForThisSystem() { assertEquals("windows-x86_64", Locate.okrunDir("Windows 11", "amd64")) @@ -46,12 +39,10 @@ class BackendTest { File(root, "backend/okrun/linux-x86_64").mkdirs() File(root, "backend/mcpp-ide.okb").writeText("") File(root, "backend/okrun/linux-x86_64/okrun").writeText("") - File(root, "bin/linux-x64").mkdirs() - File(root, "bin/linux-x64/mcpp-ide").writeText("") val linux = Locate.backend("", root, path = "", os = "Linux", arch = "amd64", home = "/nonexistent")!! assertEquals(listOf(File(root, "backend/okrun/linux-x86_64/okrun").path, File(root, "backend/mcpp-ide.okb").path), linux.command) assertEquals("bundle", linux.source) - // No okrun for this system and none on PATH: the system's own program, when the package carries one. + // No okrun for this system and none on PATH: nothing in the plugin starts. val arm = Locate.backend("", root, path = "", os = "Linux", arch = "aarch64", home = "/nonexistent") assertEquals(null, arm) root.deleteRecursively() diff --git a/src/bin/dev.cpp b/src/bin/dev.cpp index 3eb373a..0411bf3 100644 --- a/src/bin/dev.cpp +++ b/src/bin/dev.cpp @@ -271,9 +271,6 @@ void copy_tree(const fs::path& from, const fs::path& to, std::span<const std::st // --okb FILE (MCPP_IDE_OKB) the ok-image bundle, as backend/mcpp-ide.okb: one for every system // --okrun DIR (MCPP_IDE_OKRUN) okrun for each system and architecture, laid out // <os>-<arch>/okrun[.exe], as backend/okrun/ -// --backends DIR (MCPP_IDE_BACKENDS) -// programs laid out <platform>/mcpp-ide[.exe], as bin/: the form -// packages take until the bundle is built void stage_backend(std::span<const std::string> args, const fs::path& out) { auto from = [&](std::string_view flag, const char* variable) { auto v = option(args, flag); @@ -285,7 +282,6 @@ void stage_backend(std::span<const std::string> args, const fs::path& out) { fs::copy_file(*okb, out / "backend" / "mcpp-ide.okb", fs::copy_options::overwrite_existing); } if (auto okrun = from("--okrun", "MCPP_IDE_OKRUN")) copy_tree(*okrun, out / "backend" / "okrun"); - if (auto backends = from("--backends", "MCPP_IDE_BACKENDS")) copy_tree(*backends, out / "bin"); } int gen_vscode(std::span<const std::string> args) { diff --git a/vscode/README.md b/vscode/README.md index eebb51f..4a06afd 100644 --- a/vscode/README.md +++ b/vscode/README.md @@ -38,8 +38,9 @@ every build, whoever runs it; the project view says when the installed mcppls is - mcpp 2026.10.26.1 or later (`xlings install mcpp`). - The mcpp-ide backend: shipped inside the extension for every system (one ok-image bundle run by - okrun, or a program per system); otherwise `xlings install mcpp-ide`, or set - `mcpp.ide.backendPath` (a program or an `.okb`). + the okrun the extension carries for Linux x64/arm64, macOS arm64 and Windows x64, or by okrun on + PATH elsewhere); otherwise `xlings install mcpp-ide`, or set `mcpp.ide.backendPath` (a program or + an `.okb`). ## Upgrading from 0.9 diff --git a/vscode/src/backend/locate.ts b/vscode/src/backend/locate.ts index 6543672..9638e12 100644 --- a/vscode/src/backend/locate.ts +++ b/vscode/src/backend/locate.ts @@ -4,9 +4,7 @@ // 2. the bundle the extension carries, `backend/mcpp-ide.okb`, run by the okrun it carries for // this system (`backend/okrun/<os>-<arch>/okrun[.exe]`), else by okrun on PATH -- one package // for every system and architecture; -// 3. a program the extension carries for this system (`bin/<platform>/mcpp-ide[.exe]`), the form -// packages take until the bundle is built; -// 4. the mcpp-ide xlings installed (its command runs okrun on its bundle), then PATH. +// 3. the mcpp-ide xlings installed (its command runs okrun on its bundle), then PATH. import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; @@ -15,12 +13,7 @@ export interface Located { program: string; /** Arguments before the backend's own (`serve`): the bundle, when okrun runs one. */ args: string[]; - source: "setting" | "bundle" | "bundled" | "xlings" | "PATH"; -} - -/** "linux-x64", "darwin-arm64", "win32-x64": the directory under bin/ for this system. */ -export function platformDir(platform: NodeJS.Platform = process.platform, arch: string = process.arch): string { - return `${platform}-${arch}`; + source: "setting" | "bundle" | "xlings" | "PATH"; } /** mcpp's names for a system and an architecture: "linux-x86_64", "macos-aarch64", "windows-x86_64". */ @@ -86,8 +79,6 @@ export function locateBackend(options: { const runner = okrun(); if (runner) return { program: runner, args: [bundle], source: "bundle" }; } - const bundled = path.join(options.extensionRoot, "bin", platformDir(platform, arch), executable("mcpp-ide", platform)); - if (isFile(bundled)) return { program: runnable(bundled, platform), args: [], source: "bundled" }; const exe = executable("mcpp-ide", platform); const home = options.home ?? os.homedir(); for (const candidate of [ diff --git a/vscode/test/e2e/runTest.ts b/vscode/test/e2e/runTest.ts index 2a6f172..39fc2da 100644 --- a/vscode/test/e2e/runTest.ts +++ b/vscode/test/e2e/runTest.ts @@ -21,7 +21,8 @@ async function main(): Promise<void> { fs.writeFileSync(path.join(workspace, "tests", "test_smoke.cpp"), "int main() { return 0; }\n"); const user = path.join(temp, "user-data", "User"); fs.mkdirSync(user, { recursive: true }); - // MCPP_E2E_BUNDLED: the backend the staged extension carries (bin/<platform>/), as a user gets it. + // MCPP_E2E_BUNDLED: the backend the staged extension carries (backend/mcpp-ide.okb, run by the + // okrun it carries for this system), as a user gets it. fs.writeFileSync(path.join(user, "settings.json"), JSON.stringify({ ...(process.env.MCPP_E2E_BUNDLED ? {} : { "mcpp.ide.backendPath": backend }), "mcpp.path": mock, diff --git a/vscode/test/unit/locate.test.ts b/vscode/test/unit/locate.test.ts index 70a4826..2b0285d 100644 --- a/vscode/test/unit/locate.test.ts +++ b/vscode/test/unit/locate.test.ts @@ -5,27 +5,23 @@ import * as os from "node:os"; import * as path from "node:path"; import { test } from "node:test"; -import { locateBackend, okrunDir, onPath, platformDir } from "../../src/backend/locate"; +import { locateBackend, okrunDir, onPath } from "../../src/backend/locate"; import { mcpplsCandidates } from "../../src/backend/mcppls"; -test("the configured path wins, then the bundled program", () => { +test("the configured path wins: a program, or a bundle run by okrun", () => { const ext = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-ext-")); assert.deepEqual(locateBackend({ configured: "/x/mcpp-ide", extensionRoot: ext }), { program: "/x/mcpp-ide", args: [], source: "setting" }); - const dir = path.join(ext, "bin", platformDir("linux", "x64")); - fs.mkdirSync(dir, { recursive: true }); - fs.writeFileSync(path.join(dir, "mcpp-ide"), ""); - const found = locateBackend({ extensionRoot: ext, platform: "linux", arch: "x64", env: { PATH: "" }, home: "/nonexistent" }); - assert.equal(found?.source, "bundled"); - assert.equal(platformDir("win32", "x64"), "win32-x64"); + const bin = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-okrun-")); + fs.writeFileSync(path.join(bin, "okrun"), ""); + assert.deepEqual(locateBackend({ configured: "/x/mcpp-ide.okb", extensionRoot: ext, platform: "linux", arch: "x64", env: { PATH: bin } }), + { program: path.join(bin, "okrun"), args: ["/x/mcpp-ide.okb"], source: "setting" }); }); -test("the bundle runs under the okrun carried for this system, else okrun on PATH, before a native program", () => { +test("the bundle runs under the okrun carried for this system, else okrun on PATH", () => { const ext = fs.mkdtempSync(path.join(os.tmpdir(), "mcppide-okb-")); fs.mkdirSync(path.join(ext, "backend", "okrun", "linux-x86_64"), { recursive: true }); fs.writeFileSync(path.join(ext, "backend", "mcpp-ide.okb"), ""); fs.writeFileSync(path.join(ext, "backend", "okrun", "linux-x86_64", "okrun"), ""); - fs.mkdirSync(path.join(ext, "bin", "linux-x64"), { recursive: true }); - fs.writeFileSync(path.join(ext, "bin", "linux-x64", "mcpp-ide"), ""); const linux = locateBackend({ extensionRoot: ext, platform: "linux", arch: "x64", env: { PATH: "" }, home: "/nonexistent" }); assert.deepEqual(linux, { program: path.join(ext, "backend", "okrun", "linux-x86_64", "okrun"), args: [path.join(ext, "backend", "mcpp-ide.okb")], source: "bundle" }); // No okrun carried for macOS: okrun on PATH runs the bundle. @@ -34,7 +30,7 @@ test("the bundle runs under the okrun carried for this system, else okrun on PAT const mac = locateBackend({ extensionRoot: ext, platform: "darwin", arch: "arm64", env: { PATH: bin }, home: "/nonexistent" }); assert.deepEqual(mac?.args, [path.join(ext, "backend", "mcpp-ide.okb")]); assert.equal(mac?.program, path.join(bin, "okrun")); - // No okrun at all: the native program for the system, if the package carries one. + // No okrun at all: nothing in the package starts. const native = locateBackend({ extensionRoot: ext, platform: "linux", arch: "arm64", env: { PATH: "" }, home: "/nonexistent" }); assert.equal(native, undefined); assert.equal(okrunDir("win32", "x64"), "windows-x86_64"); From 67aee7eb6d099718cc68bb9c9b97cba1e6230d61 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 10:15:27 +0900 Subject: [PATCH 20/30] CI: mcpp built from MCPP_SOURCE_REF builds itself with the release its .xlings.json pins Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/actions/setup-mcpp/action.yml | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/actions/setup-mcpp/action.yml b/.github/actions/setup-mcpp/action.yml index f6bd7bb..a1c6aeb 100644 --- a/.github/actions/setup-mcpp/action.yml +++ b/.github/actions/setup-mcpp/action.yml @@ -58,8 +58,8 @@ runs: sleep 30 done mcpp toolchain default "llvm@$LLVM_VERSION" - # MCPP_SOURCE_REF: mcpp built from that ref by the release installed above, before the ref is - # released; the program is kept per commit and system, and put first on PATH. + # MCPP_SOURCE_REF: mcpp built from that ref, before the ref is released; the program is kept per + # commit and system, and put first on PATH. - name: Resolve MCPP_SOURCE_REF id: source if: env.MCPP_SOURCE_REF != '' @@ -93,7 +93,13 @@ runs: git init -q "$src" git -C "$src" fetch -q --depth 1 https://github.com/mcpp-community/mcpp.git "$SHA" git -C "$src" checkout -q FETCH_HEAD - (cd "$src" && mcpp build) + # mcpp builds itself with the release its .xlings.json pins (xlings sets the project up). + for attempt in 1 2 3; do + if (cd "$src" && xlings install -y); then break; fi + [ "$attempt" = 3 ] && { echo "::error::the mcpp $MCPP_SOURCE_REF pins could not be installed"; exit 1; } + sleep 30 + done + (cd "$src" && mcpp --version && mcpp build) built="$(find "$src/target" -type f -name "$exe" -path '*/bin/*' ! -path '*/dist/*' | head -1)" [ -n "$built" ] || { echo "::error::building mcpp at $MCPP_SOURCE_REF left no $exe"; exit 1; } mkdir -p "$bin" From 5c9dea97ddf5fa9f248acae935c240195fd06858 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 10:28:22 +0900 Subject: [PATCH 21/30] CI: the universal package is packed under its name on every system Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1487862..b491dad 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -61,7 +61,7 @@ jobs: case "$RUNNER_OS" in Linux) system=linux ;; macOS) system=macos ;; *) system=windows ;; esac package="mcpp-ide-$version-openkal" mkdir -p out - mcpp pack mcpp-ide --target "$arch-openkal" --mode self-contained --pkg-format dir + mcpp pack mcpp-ide --target "$arch-openkal" --mode self-contained --pkg-format dir -o "$package" cp -R "target/dist/$package" out/ ls -R "out/$package/libexec" if [ "$system" = windows ]; then From ade13d7e21f878389d0889f0a53b208aee0f0648 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 10:41:34 +0900 Subject: [PATCH 22/30] CI: each system's universal package travels as its archive (the mode bits and its one directory kept), and --merge joins the archives Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/workflows/ci.yml | 24 +++++++++++------------ mcpp.lock | 42 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 50 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b491dad..022affe 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -60,22 +60,24 @@ jobs: case "$(uname -m)" in x86_64|amd64|AMD64) arch=x86_64 ;; *) arch=aarch64 ;; esac case "$RUNNER_OS" in Linux) system=linux ;; macOS) system=macos ;; *) system=windows ;; esac package="mcpp-ide-$version-openkal" - mkdir -p out - mcpp pack mcpp-ide --target "$arch-openkal" --mode self-contained --pkg-format dir -o "$package" - cp -R "target/dist/$package" out/ - ls -R "out/$package/libexec" + mkdir -p out unpacked + # An archive keeps the mode bits an artifact does not, and names its one directory. + mcpp pack mcpp-ide --target "$arch-openkal" --mode self-contained --pkg-format tar -o "$package.tar.gz" + cp "target/dist/$package.tar.gz" out/ + tar -xzf "out/$package.tar.gz" -C unpacked + ls -R "unpacked/$package/libexec" if [ "$system" = windows ]; then - (cd "out/$package/bin" && cmd //c "mcpp-ide.cmd --version") + (cd "unpacked/$package/bin" && cmd //c "mcpp-ide.cmd --version") else - "out/$package/bin/mcpp-ide" --version + "unpacked/$package/bin/mcpp-ide" --version fi case " ${{ matrix.pack }} " in *" okb "*) mcpp pack mcpp-ide --target "$arch-openkal" --pkg-format okb cp "target/dist/mcpp-ide-$version.okb" out/mcpp-ide.okb - "out/$package/libexec/okrun/$system-$arch/okrun" out/mcpp-ide.okb --version - ls -l out/mcpp-ide.okb + "unpacked/$package/libexec/okrun/$system-$arch/okrun" out/mcpp-ide.okb --version ;; esac + ls -l out - uses: actions/upload-artifact@v5 if: matrix.pack != '' with: @@ -105,13 +107,11 @@ jobs: set -euo pipefail version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" package="mcpp-ide-$version-openkal" - # An artifact does not keep the mode bits. - chmod +x backends/*/"$package"/bin/mcpp-ide backends/*/"$package"/libexec/okrun/*/okrun* mkdir -p merged backend merge=() - for p in backends/*/"$package"; do merge+=(--merge "$p"); done - mcpp pack "${merge[@]}" --pkg-format dir -o "$PWD/merged/$package" + for p in backends/*/"$package.tar.gz"; do merge+=(--merge "$p"); done mcpp pack "${merge[@]}" -o "$PWD/backend/$package.tar.gz" + tar -xzf "backend/$package.tar.gz" -C merged cp backends/backend-linux-x64/mcpp-ide.okb backend/mcpp-ide.okb cp -R "merged/$package/libexec/okrun" backend/okrun python3 - "merged/$package/mcpp-package.json" <<'PY' diff --git a/mcpp.lock b/mcpp.lock index 9f6ebe5..810decc 100644 --- a/mcpp.lock +++ b/mcpp.lock @@ -10,17 +10,51 @@ version = "os-0.2.1" source = "git+https://github.com/mcpplibs/os.git#branch=os-0.2.1@211e765edbed99ef02526c45af9da988f6e48399" hash = "fnv1a:e9ea51f425a4832f" +[package."mcpp.plugins"] +namespace = "mcpp" +version = "0.20.0" +source = "index+mcpp@0.20.0" +hash = "fnv1a:9438fb3cbe77fdc7" + [package."openkal"] namespace = "mcpplibs" version = "0.17.1" source = "index+mcpplibs@0.17.1" hash = "fnv1a:d9a6fd1043f0f322" -[package."openkal-linux"] +[package."openkal-ld"] +namespace = "mcpplibs" +version = "0.1.3" +source = "index+mcpplibs@0.1.3" +hash = "fnv1a:c45ba7726c74fc44" + +[package."openkal-llvm-runtime"] +namespace = "mcpplibs" +version = "0.16.5" +source = "index+mcpplibs@0.16.5" +hash = "fnv1a:1310f23360b2e0f2" +origin = "platform" + +[package."openkal-musl"] +namespace = "mcpplibs" +version = "0.22.5" +source = "index+mcpplibs@0.22.5" +hash = "fnv1a:de2d15df84a5a92a" +origin = "platform" + +[package."openkal-platform"] +namespace = "mcpplibs" +version = "0.17.2" +source = "index+mcpplibs@0.17.2" +hash = "fnv1a:d470e712205b7b39" +origin = "platform" + +[package."openkal-tools"] namespace = "mcpplibs" -version = "0.18.2" -source = "index+mcpplibs@0.18.2" -hash = "fnv1a:2947b54ddbcf8813" +version = "0.1.3" +source = "index+mcpplibs@0.1.3" +hash = "fnv1a:3a0aa473e0da7eaf" +origin = "platform" [package."nlohmann.json"] namespace = "nlohmann" From e9e6a97d1f4a5c2957fa787b59f42ff5da2f841a Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 10:41:45 +0900 Subject: [PATCH 23/30] mcpp.lock as mcpp build writes it Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- mcpp.lock | 42 ++++-------------------------------------- 1 file changed, 4 insertions(+), 38 deletions(-) diff --git a/mcpp.lock b/mcpp.lock index 810decc..9f6ebe5 100644 --- a/mcpp.lock +++ b/mcpp.lock @@ -10,51 +10,17 @@ version = "os-0.2.1" source = "git+https://github.com/mcpplibs/os.git#branch=os-0.2.1@211e765edbed99ef02526c45af9da988f6e48399" hash = "fnv1a:e9ea51f425a4832f" -[package."mcpp.plugins"] -namespace = "mcpp" -version = "0.20.0" -source = "index+mcpp@0.20.0" -hash = "fnv1a:9438fb3cbe77fdc7" - [package."openkal"] namespace = "mcpplibs" version = "0.17.1" source = "index+mcpplibs@0.17.1" hash = "fnv1a:d9a6fd1043f0f322" -[package."openkal-ld"] -namespace = "mcpplibs" -version = "0.1.3" -source = "index+mcpplibs@0.1.3" -hash = "fnv1a:c45ba7726c74fc44" - -[package."openkal-llvm-runtime"] -namespace = "mcpplibs" -version = "0.16.5" -source = "index+mcpplibs@0.16.5" -hash = "fnv1a:1310f23360b2e0f2" -origin = "platform" - -[package."openkal-musl"] -namespace = "mcpplibs" -version = "0.22.5" -source = "index+mcpplibs@0.22.5" -hash = "fnv1a:de2d15df84a5a92a" -origin = "platform" - -[package."openkal-platform"] -namespace = "mcpplibs" -version = "0.17.2" -source = "index+mcpplibs@0.17.2" -hash = "fnv1a:d470e712205b7b39" -origin = "platform" - -[package."openkal-tools"] +[package."openkal-linux"] namespace = "mcpplibs" -version = "0.1.3" -source = "index+mcpplibs@0.1.3" -hash = "fnv1a:3a0aa473e0da7eaf" -origin = "platform" +version = "0.18.2" +source = "index+mcpplibs@0.18.2" +hash = "fnv1a:2947b54ddbcf8813" [package."nlohmann.json"] namespace = "nlohmann" From 3b50e8f5f0e6ec9ec49882eb3a0638c69863ceef Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 11:02:11 +0900 Subject: [PATCH 24/30] CI: Windows' okrun is packed on Linux (an image built on Windows is not yet the file Linux and macOS build, so --merge refuses it); macOS packs its own Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/workflows/ci.yml | 26 +++++++++++++------------- docs/architecture.md | 7 ++++--- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 022affe..92b2de5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,9 +19,12 @@ jobs: # the dev tool), run the tests -- the protocol against its schema and the fixtures against mcpp's # contract among them -- and check the translations. A `pack` leg then packs the backend as the # editor packages carry it (mcpp design 2026-10-28 part 2 §15): its universal self-contained - # package (`<arch>-openkal`: the x86_64 and aarch64 images, okrun for this system's architectures), - # and on linux-x64 the ok-image bundle. The `host-platform` row builds and tests with the build - # programs (build.mcpp, the spec/ generators) as ok images run by okrun. + # package (`<arch>-openkal`: the x86_64 and aarch64 images, okrun for the `systems` it names), and + # on linux-x64 the ok-image bundle. Windows' okrun is packed on Linux (x86_64-windows-gnu, static): + # an image built on Windows is not yet the same file as one built on Linux or macOS (its __FILE__ + # strings keep `\`), and `mcpp pack --merge` joins only packages that hold the same images. The + # `host-platform` row builds and tests with the build programs (build.mcpp, the spec/ generators) + # as ok images run by okrun. backend: name: backend (${{ matrix.platform }}${{ matrix.host-platform && format(', host platform {0}', matrix.host-platform) || '' }}) runs-on: ${{ matrix.os }} @@ -30,10 +33,10 @@ jobs: fail-fast: false matrix: include: - - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: 'package okb' } + - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: 'package okb', systems: 'linux,windows' } - { os: ubuntu-24.04-arm, platform: linux-arm64, llvm: 'false', pack: '' } - - { os: macos-14, platform: darwin-arm64, llvm: 'true', pack: 'package' } - - { os: windows-2022, platform: win32-x64, llvm: 'true', pack: 'package' } + - { os: macos-14, platform: darwin-arm64, llvm: 'true', pack: 'package', systems: 'macos' } + - { os: windows-2022, platform: win32-x64, llvm: 'true', pack: '' } - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: '', host-platform: 'openkal-platform@0.17.2' } defaults: run: @@ -58,19 +61,16 @@ jobs: set -euo pipefail version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" case "$(uname -m)" in x86_64|amd64|AMD64) arch=x86_64 ;; *) arch=aarch64 ;; esac - case "$RUNNER_OS" in Linux) system=linux ;; macOS) system=macos ;; *) system=windows ;; esac + case "$RUNNER_OS" in Linux) system=linux ;; *) system=macos ;; esac package="mcpp-ide-$version-openkal" mkdir -p out unpacked # An archive keeps the mode bits an artifact does not, and names its one directory. - mcpp pack mcpp-ide --target "$arch-openkal" --mode self-contained --pkg-format tar -o "$package.tar.gz" + mcpp pack mcpp-ide --target "$arch-openkal" --mode self-contained --systems "${{ matrix.systems }}" \ + --pkg-format tar -o "$package.tar.gz" cp "target/dist/$package.tar.gz" out/ tar -xzf "out/$package.tar.gz" -C unpacked ls -R "unpacked/$package/libexec" - if [ "$system" = windows ]; then - (cd "unpacked/$package/bin" && cmd //c "mcpp-ide.cmd --version") - else - "unpacked/$package/bin/mcpp-ide" --version - fi + "unpacked/$package/bin/mcpp-ide" --version case " ${{ matrix.pack }} " in *" okb "*) mcpp pack mcpp-ide --target "$arch-openkal" --pkg-format okb cp "target/dist/mcpp-ide-$version.okb" out/mcpp-ide.okb diff --git a/docs/architecture.md b/docs/architecture.md index 64713bf..f8ac589 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -41,12 +41,13 @@ editor package carries that bundle and the runner that starts it on each system: | Layout in the package | Holds | Started as | |---|---|---| | `backend/mcpp-ide.okb` | the x86_64 and aarch64 images | | -| `backend/okrun/<os>-<arch>/okrun[.exe]` | okrun for `linux-x86_64`, `linux-aarch64`, `macos-aarch64`, `windows-x86_64`, from `mcpp pack --mode self-contained` on each system | `okrun mcpp-ide.okb serve`: the okrun carried for this system, else okrun on PATH | +| `backend/okrun/<os>-<arch>/okrun[.exe]` | okrun for `linux-x86_64`, `linux-aarch64`, `macos-aarch64`, `windows-x86_64`: the universal self-contained packages (`mcpp pack --mode self-contained`) packed on Linux (`--systems linux,windows`) and on macOS, joined by `mcpp pack --merge` | `okrun mcpp-ide.okb serve`: the okrun carried for this system, else okrun on PATH | Before it, a configured `mcpp.ide.backendPath` (a program or an `.okb`) is used; after it, an installed `mcpp-ide` (xlings, whose command runs okrun on its bundle) or one on PATH. CI builds the -bundle once, takes okrun from each system's self-contained package, opens both editor packages on -every system and starts what they carry for it (`.github/scripts/check-package.sh`). +bundle once, joins the self-contained packages (`mcpp-ide-<version>-openkal.tar.gz`, a release asset), +takes okrun from the joined package, opens both editor packages and the joined package on every +system and starts what they carry for it (`.github/scripts/check-package.sh`). ## Generated declarations From c540adcaf997995b10c7718ca8d9b0e6af75cd1d Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 11:33:21 +0900 Subject: [PATCH 25/30] e2e: each run checks the backend it started is the one it asked for (the setting's, or the bundle the extension carries) Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- vscode/src/session.ts | 5 +++++ vscode/test/e2e/runTest.ts | 2 +- vscode/test/e2e/suite/index.ts | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/vscode/src/session.ts b/vscode/src/session.ts index 6d8b17a..7517119 100644 --- a/vscode/src/session.ts +++ b/vscode/src/session.ts @@ -45,6 +45,11 @@ export class Session implements vscode.Disposable { ); } + /** The backend's command and where it was found. */ + get started(): Located | undefined { + return this.located; + } + get info(): InitializeResult | undefined { return this.initResult; } diff --git a/vscode/test/e2e/runTest.ts b/vscode/test/e2e/runTest.ts index 39fc2da..7089dee 100644 --- a/vscode/test/e2e/runTest.ts +++ b/vscode/test/e2e/runTest.ts @@ -39,7 +39,7 @@ async function main(): Promise<void> { "--disable-gpu", "--disable-workspace-trust", "--skip-welcome", "--skip-release-notes", // No display (a container, an agent's shell): Chromium's headless platform. ...(process.env.MCPP_E2E_HEADLESS ? ["--ozone-platform=headless"] : [])], - extensionTestsEnv: { MCPPIDE_E2E_WORKSPACE: workspace }, + extensionTestsEnv: { MCPPIDE_E2E_WORKSPACE: workspace, MCPPIDE_E2E_SOURCE: process.env.MCPP_E2E_BUNDLED ? "bundle" : "setting" }, }); } diff --git a/vscode/test/e2e/suite/index.ts b/vscode/test/e2e/suite/index.ts index 931d998..7723c1d 100644 --- a/vscode/test/e2e/suite/index.ts +++ b/vscode/test/e2e/suite/index.ts @@ -24,6 +24,8 @@ const cases: [string, (api: McppApi) => Promise<void>][] = [ assert.ok(declared.length > 40); }], ["the backend found the project and mcpp", async (api) => { + // As the run asked: the backend the settings name, or the bundle the extension carries. + assert.equal(api.session.started?.source, process.env.MCPPIDE_E2E_SOURCE); const info = api.session.info!; assert.equal(info.projects.length, 1); assert.equal(info.projects[0].name, "app"); From 83ad846821d51a549b46e4e6688d4ec3b3cc8dc2 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 12:17:26 +0900 Subject: [PATCH 26/30] openkal-platform 0.17.3: the ok images, the host-platform row, and the fixtures recaptured from mcpp release/2026.10.27.1 at 7c5ee0bb (openkal-musl 0.22.6, openkal-llvm-runtime 0.16.6); mcpp.lock as that mcpp writes it, the platform's packages beside the system's Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/versions.env | 2 +- .github/workflows/ci.yml | 2 +- CHANGELOG.md | 2 +- README.md | 2 +- README.zh-CN.md | 2 +- mcpp.lock | 42 + protocol/fixtures/build-database.json | 14 +- protocol/fixtures/build-failed.ndjson | 2 +- protocol/fixtures/build-ok.ndjson | 2 +- protocol/fixtures/build-platform.ndjson | 3815 +++++++++-------- protocol/fixtures/cache-list.json | 60 +- protocol/fixtures/result-ok.json | 6 +- protocol/fixtures/test.ndjson | 4 +- .../fixtures/toolchain-list-platform.json | 4 +- protocol/fixtures/toolchain-list.json | 4 +- protocol/mcpp-contract.schema.json | 2 +- 16 files changed, 2019 insertions(+), 1946 deletions(-) diff --git a/.github/versions.env b/.github/versions.env index 3a45f79..756b43b 100644 --- a/.github/versions.env +++ b/.github/versions.env @@ -3,7 +3,7 @@ MCPP_VERSION=2026.10.26.2 # Until mcpp 2026.10.27.1 is released: the ref of mcpp-community/mcpp CI builds and uses, whose control # contract the fixtures were captured from (protocol/fixtures/version.txt) and whose platforms -# (openkal-platform 0.17.2) the backend's ok images are built on. Empty: the release above is used. +# (openkal-platform 0.17.3) the backend's ok images are built on. Empty: the release above is used. MCPP_SOURCE_REF=release/2026.10.27.1 # The LLVM the backend builds with on macOS and Windows (the targets mcpp reaches there with it). LLVM_VERSION=23.1.3 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92b2de5..f7faf72 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,7 +37,7 @@ jobs: - { os: ubuntu-24.04-arm, platform: linux-arm64, llvm: 'false', pack: '' } - { os: macos-14, platform: darwin-arm64, llvm: 'true', pack: 'package', systems: 'macos' } - { os: windows-2022, platform: win32-x64, llvm: 'true', pack: '' } - - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: '', host-platform: 'openkal-platform@0.17.2' } + - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: '', host-platform: 'openkal-platform@0.17.3' } defaults: run: shell: bash diff --git a/CHANGELOG.md b/CHANGELOG.md index 2d8003c..bd01839 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,6 @@ The first release of mcpp-ide: one backend for mcpp's editor integrations, the V - CLion: run configurations with a PTY console, test tree, CLion's debugger, console links, the mcpp tool window; depends on the mcppls CLion plugin. - One package per editor for every system: the backend as one ok-image bundle (x86_64 and aarch64 - images on openkal-platform 0.17.2) with okrun for Linux x86_64/aarch64, macOS arm64 and Windows + images on openkal-platform 0.17.3) with okrun for Linux x86_64/aarch64, macOS arm64 and Windows x64; CI starts it from both packages on each of those systems. - `mcpp pack`'s package format is passed as `--pkg-format` where mcpp offers it (`--format` before). diff --git a/README.md b/README.md index 31bccfd..165ec15 100644 --- a/README.md +++ b/README.md @@ -57,7 +57,7 @@ on my mcpp project. | Agents, other clients | `mcpp-ide-<version>-openkal.tar.gz` (both images; okrun for Linux x64/arm64, macOS arm64, Windows x64), `mcpp-ide-<version>.okb` with okrun, or `xlings install mcpp-ide` | run `bin/mcpp-ide serve` (`bin\mcpp-ide.cmd` on Windows), or `okrun mcpp-ide-<version>.okb serve` | Each editor package serves every system: it carries the backend as one ok-image bundle -(`backend/mcpp-ide.okb`, the x86_64 and aarch64 images on openkal-platform 0.17.2) and okrun for +(`backend/mcpp-ide.okb`, the x86_64 and aarch64 images on openkal-platform 0.17.3) and okrun for Linux x64/arm64, macOS arm64 and Windows x64. ### From source diff --git a/README.zh-CN.md b/README.zh-CN.md index d79a58e..4d760b3 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -51,7 +51,7 @@ C++ 文件的语言功能来自 [mcppls](https://github.com/Sunrisepeak/mcpp-lan | CLion 2025.2+ | JetBrains Marketplace(`mcpp-clion`),或 `mcpp-clion-<version>.zip` | Settings → Plugins → Install Plugin from Disk;先安装 mcppls CLion 插件 | | Agent、其他客户端 | `mcpp-ide-<version>-openkal.tar.gz`(两个架构的映像;Linux x64/arm64、macOS arm64、Windows x64 的 okrun),携带 okrun 的 `mcpp-ide-<version>.okb`,或 `xlings install mcpp-ide` | 运行 `bin/mcpp-ide serve`(Windows 上为 `bin\mcpp-ide.cmd`),或 `okrun mcpp-ide-<version>.okb serve` | -每个编辑器包都服务全部系统:后端以一个 ok 映像包(`backend/mcpp-ide.okb`,openkal-platform 0.17.2 上的 +每个编辑器包都服务全部系统:后端以一个 ok 映像包(`backend/mcpp-ide.okb`,openkal-platform 0.17.3 上的 x86_64 与 aarch64 映像)加上 Linux x64/arm64、macOS arm64、Windows x64 的 okrun 携带。 ### 从源码构建 diff --git a/mcpp.lock b/mcpp.lock index 9f6ebe5..35291b8 100644 --- a/mcpp.lock +++ b/mcpp.lock @@ -10,18 +10,60 @@ version = "os-0.2.1" source = "git+https://github.com/mcpplibs/os.git#branch=os-0.2.1@211e765edbed99ef02526c45af9da988f6e48399" hash = "fnv1a:e9ea51f425a4832f" +[package."mcpp.plugins"] +namespace = "mcpp" +version = "0.20.0" +source = "index+mcpp@0.20.0" +hash = "fnv1a:9438fb3cbe77fdc7" +origin = "platform" + [package."openkal"] namespace = "mcpplibs" version = "0.17.1" source = "index+mcpplibs@0.17.1" hash = "fnv1a:d9a6fd1043f0f322" +[package."openkal-ld"] +namespace = "mcpplibs" +version = "0.1.3" +source = "index+mcpplibs@0.1.3" +hash = "fnv1a:c45ba7726c74fc44" +origin = "platform" + [package."openkal-linux"] namespace = "mcpplibs" version = "0.18.2" source = "index+mcpplibs@0.18.2" hash = "fnv1a:2947b54ddbcf8813" +[package."openkal-llvm-runtime"] +namespace = "mcpplibs" +version = "0.16.6" +source = "index+mcpplibs@0.16.6" +hash = "fnv1a:1310f13360b2df3f" +origin = "platform" + +[package."openkal-musl"] +namespace = "mcpplibs" +version = "0.22.6" +source = "index+mcpplibs@0.22.6" +hash = "fnv1a:de2d14df84a5a777" +origin = "platform" + +[package."openkal-platform"] +namespace = "mcpplibs" +version = "0.17.3" +source = "index+mcpplibs@0.17.3" +hash = "fnv1a:d470e612205b7986" +origin = "platform" + +[package."openkal-tools"] +namespace = "mcpplibs" +version = "0.1.3" +source = "index+mcpplibs@0.1.3" +hash = "fnv1a:3a0aa473e0da7eaf" +origin = "platform" + [package."nlohmann.json"] namespace = "nlohmann" version = "3.12.0" diff --git a/protocol/fixtures/build-database.json b/protocol/fixtures/build-database.json index 75919de..54aa642 100644 --- a/protocol/fixtures/build-database.json +++ b/protocol/fixtures/build-database.json @@ -60,20 +60,20 @@ "-c", "@ROOT@/src/main.cpp", "-o", - "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/main.o" + "@HOME@/.mcpp/cache/build-database/9b4f7fd6a357f81e/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/main.o" ], "ide": { "role": "non-module" }, "local-arguments": [], - "object": "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/main.o", + "object": "@HOME@/.mcpp/cache/build-database/9b4f7fd6a357f81e/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/main.o", "private": false, "provides": {}, "requires": [ "std" ], "source": "@ROOT@/src/main.cpp", - "work-directory": "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416" + "work-directory": "@HOME@/.mcpp/cache/build-database/9b4f7fd6a357f81e/target/x86_64-linux-gnu/77ba4e6c37abd416" } ], "visible-sets": [ @@ -114,20 +114,20 @@ "-c", "@ROOT@/tests/test_smoke.cpp", "-o", - "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/test_smoke.o" + "@HOME@/.mcpp/cache/build-database/9b4f7fd6a357f81e/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/test_smoke.o" ], "ide": { "role": "non-module" }, "local-arguments": [], - "object": "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/test_smoke.o", + "object": "@HOME@/.mcpp/cache/build-database/9b4f7fd6a357f81e/target/x86_64-linux-gnu/77ba4e6c37abd416/obj/test_smoke.o", "private": false, "provides": {}, "requires": [ "std" ], "source": "@ROOT@/tests/test_smoke.cpp", - "work-directory": "@HOME@/.mcpp/cache/build-database/126ff31568829a01/target/x86_64-linux-gnu/77ba4e6c37abd416" + "work-directory": "@HOME@/.mcpp/cache/build-database/9b4f7fd6a357f81e/target/x86_64-linux-gnu/77ba4e6c37abd416" } ], "visible-sets": [ @@ -186,7 +186,7 @@ ], "version": 1 }, - "inputs-fingerprint": "fnv1a:dacb6fd7fa58be28", + "inputs-fingerprint": "fnv1a:044b186c2cfb5ae7", "spec": { "name": "s1", "version": "0.3.0" diff --git a/protocol/fixtures/build-failed.ndjson b/protocol/fixtures/build-failed.ndjson index 6bd1a04..a791dc1 100644 --- a/protocol/fixtures/build-failed.ndjson +++ b/protocol/fixtures/build-failed.ndjson @@ -3,4 +3,4 @@ {"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":2} {"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":2} {"diagnostic":{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"},"event":"diagnostic","kind":"mcpp.event","schemaVersion":1} -{"data":{"artifacts":[],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/compile_commands.json","configuration":{"fingerprint":"77ba4e6c37abd416","hostPlatform":null,"outputDir":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416","platform":null,"profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"}],"finishedAt":1793148661270,"pid":1209305,"startedAt":1793148661248,"status":"failed"},"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"build failed in app v0.1.0 (.)","severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} +{"data":{"artifacts":[],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/compile_commands.json","configuration":{"fingerprint":"77ba4e6c37abd416","hostPlatform":null,"outputDir":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416","platform":null,"profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[{"message":"'undeclared_name' was not declared in this scope","path":"@ROOT@/src/main.cpp","range":{"end":{"column":21,"line":1},"start":{"column":21,"line":1}},"severity":"error"}],"finishedAt":1793166359301,"pid":3253117,"startedAt":1793166359280,"status":"failed"},"diagnostics":[{"code":"MCPP_BUILD_FAILED","message":"build failed in app v0.1.0 (.)","severity":"error","source":"mcpp"}],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} diff --git a/protocol/fixtures/build-ok.ndjson b/protocol/fixtures/build-ok.ndjson index c6fd72b..dfc51c7 100644 --- a/protocol/fixtures/build-ok.ndjson +++ b/protocol/fixtures/build-ok.ndjson @@ -6,4 +6,4 @@ {"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":4} {"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":4} {"artifact":{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"},"event":"artifact","kind":"mcpp.event","schemaVersion":1} -{"data":{"artifacts":[{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"}],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/compile_commands.json","configuration":{"fingerprint":"77ba4e6c37abd416","hostPlatform":null,"outputDir":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416","platform":null,"profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[],"finishedAt":1793148650353,"pid":1203929,"startedAt":1793148649554,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} +{"data":{"artifacts":[{"kind":"bin","launch":{"argv":["@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"],"cwd":"@ROOT@","env":{"GBM_BACKENDS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/gbm:@HOME@/.xlings/subos/speak-agent-private/usr/lib/gbm","LIBGL_DRIVERS_PATH":"@HOME@/.mcpp/registry/subos/default/usr/lib/dri:@HOME@/.xlings/subos/speak-agent-private/usr/lib/dri","XDG_DATA_DIRS":"@HOME@/.mcpp/registry/subos/default/share:@HOME@/.xlings/subos/speak-agent-private/share:/usr/share/ubuntu:/usr/share/gnome:/usr/local/share/:/usr/share/:/var/lib/snapd/desktop","__EGL_VENDOR_LIBRARY_DIRS":"@HOME@/.mcpp/registry/subos/default/share/glvnd/egl_vendor.d:@HOME@/.xlings/subos/speak-agent-private/share/glvnd/egl_vendor.d"},"via":null},"name":"app","path":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/bin/app"}],"client":"mcpp-ide-fixtures","command":"mcpp build --message-format json","compileDatabase":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416/compile_commands.json","configuration":{"fingerprint":"77ba4e6c37abd416","hostPlatform":null,"outputDir":"@ROOT@/target/x86_64-linux-gnu/77ba4e6c37abd416","platform":null,"profile":"dev","triple":"x86_64-linux-gnu"},"diagnostics":[],"finishedAt":1793166350218,"pid":3248166,"startedAt":1793166349536,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} diff --git a/protocol/fixtures/build-platform.ndjson b/protocol/fixtures/build-platform.ndjson index 19c41b4..b2ee8e5 100644 --- a/protocol/fixtures/build-platform.ndjson +++ b/protocol/fixtures/build-platform.ndjson @@ -1,1893 +1,1924 @@ -{"configuration":{"fingerprint":"38fc4cae0272ddf9","hostPlatform":null,"outputDir":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9","platform":{"fields":{"carrier":{"source":"platform","value":"openkal-run@0.1.3"},"layers.c++-abi":{"source":"platform","value":"openkal-llvm-runtime@0.16.5"},"layers.c-abi":{"source":"platform","value":"openkal-musl@0.22.5"},"layers.compiler-runtime":{"source":"platform","value":"openkal-llvm-runtime@0.16.5"},"link.driver":{"source":"platform","value":"lld"},"link.exe":{"source":"platform","value":"{name}.oke"},"link.shared":{"source":"platform","value":"lib{name}.okso"},"link.start":{"source":"platform","value":"ok_main"},"runner":{"source":"platform","value":["okrun","{}"]},"toolchain":{"source":"platform","value":"llvm@23.1.3"},"tools.okld":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/0daa33111e083da8/bin/okld"},"tools.okrun":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/3e48df0058ef2949/bin/okrun"}},"hosted":false,"name":"openkal-platform","source":"built-in","version":"0.17.2"},"profile":"dev","triple":"aarch64-openkal"},"event":"plan","kind":"mcpp.event","schemaVersion":1} -{"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":5,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":6,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":7,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":8,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":9,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":10,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":11,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":12,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":13,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":14,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":15,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":16,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":17,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":18,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":19,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":20,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":21,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":22,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":23,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":24,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":25,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":26,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":27,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":28,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":29,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":30,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":31,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":32,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":33,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":34,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":35,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":36,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":37,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":38,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":39,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":40,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":41,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":42,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":43,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":44,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":45,"kind":"mcpp.event","schemaVersion":1,"total":45} -{"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":5,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":6,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":7,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":8,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":9,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":10,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":11,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":12,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":13,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":14,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":15,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":16,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":17,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":18,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":19,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":20,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":21,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":22,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":23,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":24,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":25,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":26,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":27,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":28,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":29,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":30,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":31,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":32,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":33,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":34,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":35,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":36,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":37,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":38,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":39,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":40,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":41,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":42,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":43,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":44,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":45,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":46,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":47,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":48,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":49,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":50,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":51,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":52,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":53,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":54,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":55,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":56,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":57,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":58,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":59,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":60,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":61,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":62,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":63,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":64,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":65,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":66,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":67,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":68,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":69,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":70,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":71,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":72,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":73,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":74,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":75,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":76,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":77,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":78,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":79,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":80,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":81,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":82,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":83,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":84,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":85,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":86,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":87,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":88,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":89,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":90,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":91,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":92,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":93,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":94,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":95,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":96,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":97,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":98,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":99,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":100,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":101,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":102,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":103,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":104,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":105,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":106,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":107,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":108,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":109,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":110,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":111,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":112,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":113,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":114,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":115,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":116,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":117,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":118,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":119,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":120,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":121,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":122,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":123,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":124,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":125,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":126,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":127,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":128,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":129,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":130,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":131,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":132,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":133,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":134,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":135,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":136,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":137,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":138,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":139,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":140,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":141,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":142,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":143,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":144,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":145,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":146,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":147,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":148,"kind":"mcpp.event","schemaVersion":1,"total":148} -{"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":5,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":6,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":7,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":8,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":9,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":10,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":11,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":12,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":13,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":14,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":15,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":16,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":17,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":18,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":19,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":20,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":21,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":22,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":23,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":24,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":25,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":26,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":27,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":28,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":29,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":30,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":31,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":32,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":33,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":34,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":35,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":36,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":37,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":38,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":39,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":40,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":41,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":42,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":43,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":44,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":45,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":46,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":47,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":48,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":49,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":50,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":51,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":52,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":53,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":54,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":55,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":56,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":57,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":58,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":59,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":60,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":61,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":62,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":63,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":64,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":65,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":66,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":67,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":68,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":69,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":70,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":71,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":72,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":73,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":74,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":75,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":76,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":77,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":78,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":79,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":80,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":81,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":82,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":83,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":84,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":85,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":86,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":87,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":88,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":89,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":90,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":91,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":92,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":93,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":94,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":95,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":96,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":97,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":98,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":99,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":100,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":101,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":102,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":103,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":104,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":105,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":106,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":107,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":108,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":109,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":110,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":111,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":112,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":113,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":114,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":115,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":116,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":117,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":118,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":119,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":120,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":121,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":122,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":123,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":124,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":125,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":126,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":127,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":128,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":129,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":130,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":131,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":132,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":133,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":134,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":135,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":136,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":137,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":138,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":139,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":140,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":141,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":142,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":143,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":144,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":145,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":146,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":147,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":148,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":149,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":150,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":151,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":152,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":153,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":154,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":155,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":156,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":157,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":158,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":159,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":160,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":161,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":162,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":163,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":164,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":165,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":166,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":167,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":168,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":169,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":170,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":171,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":172,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":173,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":174,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":175,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":176,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":177,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":178,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":179,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":180,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":181,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":182,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":183,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":184,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":185,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":186,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":187,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":188,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":189,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":190,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":191,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":192,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":193,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":194,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":195,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":196,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":197,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":198,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":199,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":200,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":201,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":202,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":203,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":204,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":205,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":206,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":207,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":208,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":209,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":210,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":211,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":212,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":213,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":214,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":215,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":216,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":217,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":218,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":219,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":220,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":221,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":222,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":223,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":224,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":225,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":226,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":227,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":228,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":229,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":230,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":231,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":232,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":233,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":234,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":235,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":236,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":237,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":238,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":239,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":240,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":241,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":242,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":243,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":244,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":245,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":246,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":247,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":248,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":249,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":250,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":251,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":252,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":253,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":254,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":255,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":256,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":257,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":258,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":259,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":260,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":261,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":262,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":263,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":264,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":265,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":266,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":267,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":268,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":269,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":270,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":271,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":272,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":273,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":274,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":275,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":276,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":277,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":278,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":279,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":280,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":281,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":282,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":283,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":284,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":285,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":286,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":287,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":288,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":289,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":290,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":291,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":292,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":293,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":294,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":295,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":296,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":297,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":298,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":299,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":300,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":301,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":302,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":303,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":304,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":305,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":306,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":307,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":308,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":309,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":310,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":311,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":312,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":313,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":314,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":315,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":316,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":317,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":318,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":319,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":320,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":321,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":322,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":323,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":324,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":325,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":326,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":327,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":328,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":329,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":330,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":331,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":332,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":333,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":334,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":335,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":336,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":337,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":338,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":339,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":340,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":341,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":342,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":343,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":344,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":345,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":346,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":347,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":348,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":349,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":350,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":351,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":352,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":353,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":354,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":355,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":356,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":357,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":358,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":359,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":360,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":361,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":362,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":363,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":364,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":365,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":366,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":367,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":368,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":369,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":370,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":371,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":372,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":373,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":374,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":375,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":376,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":377,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":378,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":379,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":380,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":381,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":382,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":383,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":384,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":385,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":386,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":387,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":388,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":389,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":390,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":391,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":392,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":393,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":394,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":395,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":396,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":397,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":398,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":399,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":400,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":401,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":402,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":403,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":404,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":405,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":406,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":407,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":408,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":409,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":410,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":411,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":412,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":413,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":414,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":415,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":416,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":417,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":418,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":419,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":420,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":421,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":422,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":423,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":424,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":425,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":426,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":427,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":428,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":429,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":430,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":431,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":432,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":433,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":434,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":435,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":436,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":437,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":438,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":439,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":440,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":441,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":442,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":443,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":444,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":445,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":446,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":447,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":448,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":449,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":450,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":451,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":452,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":453,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":454,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":455,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":456,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":457,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":458,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":459,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":460,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":461,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":462,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":463,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":464,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":465,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":466,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":467,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":468,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":469,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":470,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":471,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":472,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":473,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":474,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":475,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":476,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":477,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":478,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":479,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":480,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":481,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":482,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":483,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":484,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":485,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":486,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":487,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":488,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":489,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":490,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":491,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":492,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":493,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":494,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":495,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":496,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":497,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":498,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":499,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":500,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":501,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":502,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":503,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":504,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":505,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":506,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":507,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":508,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":509,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":510,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":511,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":512,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":513,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":514,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":515,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":516,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":517,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":518,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":519,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":520,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":521,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":522,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":523,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":524,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":525,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":526,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":527,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":528,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":529,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":530,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":531,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":532,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":533,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":534,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":535,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":536,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":537,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":538,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":539,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":540,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":541,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":542,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":543,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":544,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":545,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":546,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":547,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":548,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":549,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":550,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":551,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":552,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":553,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":554,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":555,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":556,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":557,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":558,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":559,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":560,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":561,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":562,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":563,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":564,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":565,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":566,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":567,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":568,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":569,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":570,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":571,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":572,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":573,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":574,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":575,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":576,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":577,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":578,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":579,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":580,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":581,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":582,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":583,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":584,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":585,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":586,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":587,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":588,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":589,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":590,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":591,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":592,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":593,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":594,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":595,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":596,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":597,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":598,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":599,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":600,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":601,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":602,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":603,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":604,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":605,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":606,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":607,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":608,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":609,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":610,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":611,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":612,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":613,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":614,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":615,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":616,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":617,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":618,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":619,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":620,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":621,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":622,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":623,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":624,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":625,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":626,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":627,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":628,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":629,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":630,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":631,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":632,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":633,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":634,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":635,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":636,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":637,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":638,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":639,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":640,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":641,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":642,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":643,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":644,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":645,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":646,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":647,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":648,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":649,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":650,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":651,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":652,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":653,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":654,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":655,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":656,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":657,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":658,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":659,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":660,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":661,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":662,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":663,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":664,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":665,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":666,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":667,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":668,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":669,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":670,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":671,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":672,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":673,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":674,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":675,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":676,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":677,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":678,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":679,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":680,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":681,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":682,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":683,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":684,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":685,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":686,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":687,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":688,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":689,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":690,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":691,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":692,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":693,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":694,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":695,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":696,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":697,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":698,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":699,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":700,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":701,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":702,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":703,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":704,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":705,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":706,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":707,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":708,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":709,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":710,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":711,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":712,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":713,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":714,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":715,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":716,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":717,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":718,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":719,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":720,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":721,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":722,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":723,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":724,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":725,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":726,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":727,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":728,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":729,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":730,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":731,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":732,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":733,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":734,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":735,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":736,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":737,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":738,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":739,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":740,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":741,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":742,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":743,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":744,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":745,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":746,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":747,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":748,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":749,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":750,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":751,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":752,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":753,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":754,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":755,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":756,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":757,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":758,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":759,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":760,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":761,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":762,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":763,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":764,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":765,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":766,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":767,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":768,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":769,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":770,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":771,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":772,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":773,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":774,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":775,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":776,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":777,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":778,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":779,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":780,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":781,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":782,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":783,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":784,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":785,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":786,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":787,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":788,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":789,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":790,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":791,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":792,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":793,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":794,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":795,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":796,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":797,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":798,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":799,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":800,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":801,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":802,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":803,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":804,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":805,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":806,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":807,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":808,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":809,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":810,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":811,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":812,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":813,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":814,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":815,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":816,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":817,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":818,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":819,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":820,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":821,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":822,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":823,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":824,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":825,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":826,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":827,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":828,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":829,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":830,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":831,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":832,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":833,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":834,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":835,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":836,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":837,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":838,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":839,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":840,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":841,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":842,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":843,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":844,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":845,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":846,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":847,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":848,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":849,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":850,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":851,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":852,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":853,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":854,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":855,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":856,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":857,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":858,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":859,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":860,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":861,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":862,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":863,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":864,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":865,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":866,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":867,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":868,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":869,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":870,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":871,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":872,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":873,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":874,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":875,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":876,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":877,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":878,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":879,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":880,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":881,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":882,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":883,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":884,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":885,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":886,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":887,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":888,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":889,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":890,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":891,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":892,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":893,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":894,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":895,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":896,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":897,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":898,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":899,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":900,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":901,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":902,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":903,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":904,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":905,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":906,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":907,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":908,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":909,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":910,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":911,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":912,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":913,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":914,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":915,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":916,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":917,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":918,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":919,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":920,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":921,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":922,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":923,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":924,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":925,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":926,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":927,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":928,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":929,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":930,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":931,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":932,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":933,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":934,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":935,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":936,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":937,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":938,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":939,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":940,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":941,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":942,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":943,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":944,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":945,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":946,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":947,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":948,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":949,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":950,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":951,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":952,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":953,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":954,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":955,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":956,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":957,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":958,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":959,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":960,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":961,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":962,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":963,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":964,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":965,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":966,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":967,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":968,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":969,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":970,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":971,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":972,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":973,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":974,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":975,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":976,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":977,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":978,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":979,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":980,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":981,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":982,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":983,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":984,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":985,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":986,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":987,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":988,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":989,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":990,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":991,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":992,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":993,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":994,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":995,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":996,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":997,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":998,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":999,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1000,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1001,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1002,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1003,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1004,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1005,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1006,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1007,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1008,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1009,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1010,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1011,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1012,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1013,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1014,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1015,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1016,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1017,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1018,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1019,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1020,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1021,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1022,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1023,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1024,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1025,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1026,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1027,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1028,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1029,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1030,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1031,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1032,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1033,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1034,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1035,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1036,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1037,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1038,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1039,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1040,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1041,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1042,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1043,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1044,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1045,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1046,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1047,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1048,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1049,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1050,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1051,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1052,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1053,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1054,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1055,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1056,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1057,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1058,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1059,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1060,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1061,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1062,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1063,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1064,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1065,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1066,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1067,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1068,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1069,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1070,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1071,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1072,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1073,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1074,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1075,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1076,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1077,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1078,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1079,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1080,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1081,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1082,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1083,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1084,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1085,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1086,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1087,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1088,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1089,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1090,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1091,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1092,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1093,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1094,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1095,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1096,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1097,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1098,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1099,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1100,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1101,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1102,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1103,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1104,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1105,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1106,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1107,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1108,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1109,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1110,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1111,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1112,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1113,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1114,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1115,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1116,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1117,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1118,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1119,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1120,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1121,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1122,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1123,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1124,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1125,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1126,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1127,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1128,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1129,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1130,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1131,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1132,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1133,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1134,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1135,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1136,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1137,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1138,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1139,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1140,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1141,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1142,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1143,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1144,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1145,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1146,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1147,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1148,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1149,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1150,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1151,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1152,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1153,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1154,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1155,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1156,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1157,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1158,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1159,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1160,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1161,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1162,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1163,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1164,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1165,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1166,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1167,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1168,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1169,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1170,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1171,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1172,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1173,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1174,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1175,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1176,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1177,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1178,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1179,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1180,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1181,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1182,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1183,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1184,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1185,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1186,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1187,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1188,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1189,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1190,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1191,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1192,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1193,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1194,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1195,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1196,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1197,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1198,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1199,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1200,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1201,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1202,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1203,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1204,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1205,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1206,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1207,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1208,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1209,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1210,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1211,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1212,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1213,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1214,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1215,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1216,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1217,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1218,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1219,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1220,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1221,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1222,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1223,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1224,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1225,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1226,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1227,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1228,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1229,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1230,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1231,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1232,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1233,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1234,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1235,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1236,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1237,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1238,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1239,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1240,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1241,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1242,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1243,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1244,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1245,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1246,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1247,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1248,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1249,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1250,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1251,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1252,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1253,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1254,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1255,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1256,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1257,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1258,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1259,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1260,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1261,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1262,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1263,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1264,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1265,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1266,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1267,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1268,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1269,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1270,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1271,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1272,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1273,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1274,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1275,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1276,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1277,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1278,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1279,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1280,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1281,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1282,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1283,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1284,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1285,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1286,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1287,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1288,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1289,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1290,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1291,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1292,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1293,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1294,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1295,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1296,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1297,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1298,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1299,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1300,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1301,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1302,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1303,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1304,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1305,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1306,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1307,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1308,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1309,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1310,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1311,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1312,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1313,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1314,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1315,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1316,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1317,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1318,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1319,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1320,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1321,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1322,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1323,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1324,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1325,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1326,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1327,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1328,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1329,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1330,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1331,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1332,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1333,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1334,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1335,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1336,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1337,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1338,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1339,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1340,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1341,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1342,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1343,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1344,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1345,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1346,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1347,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1348,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1349,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1350,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1351,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1352,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1353,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1354,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1355,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1356,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1357,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1358,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1359,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1360,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1361,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1362,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1363,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1364,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1365,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1366,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1367,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1368,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1369,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1370,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1371,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1372,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1373,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1374,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1375,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1376,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1377,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1378,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1379,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1380,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1381,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1382,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1383,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1384,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1385,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1386,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1387,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1388,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1389,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1390,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1391,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1392,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1393,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1394,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1395,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1396,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1397,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1398,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1399,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1400,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1401,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1402,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1403,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1404,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1405,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1406,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1407,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1408,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1409,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1410,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1411,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1412,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1413,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1414,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1415,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1416,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1417,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1418,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1419,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1420,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1421,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1422,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1423,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1424,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1425,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1426,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1427,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1428,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1429,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1430,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1431,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1432,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1433,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1434,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1435,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1436,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1437,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1438,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1439,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1440,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1441,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1442,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1443,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1444,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1445,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1446,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1447,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1448,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1449,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1450,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1451,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1452,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1453,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1454,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1455,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1456,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1457,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1458,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1459,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1460,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1461,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1462,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1463,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1464,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1465,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1466,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1467,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1468,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1469,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1470,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1471,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1472,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1473,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1474,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1475,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1476,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1477,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1478,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1479,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1480,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1481,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1482,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1483,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1484,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1485,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1486,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1487,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1488,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1489,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1490,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1491,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1492,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1493,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1494,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1495,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1496,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1497,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1498,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1499,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1500,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1501,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1502,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1503,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1504,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1505,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1506,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1507,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1508,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1509,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1510,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1511,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1512,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1513,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1514,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1515,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1516,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1517,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1518,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1519,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1520,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1521,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1522,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1523,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1524,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1525,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1526,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1527,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1528,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1529,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1530,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1531,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1532,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1533,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1534,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1535,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1536,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1537,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1538,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1539,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1540,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1541,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1542,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1543,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1544,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1545,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1546,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1547,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1548,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1549,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1550,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1551,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1552,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1553,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1554,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1555,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1556,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1557,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1558,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1559,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1560,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1561,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1562,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1563,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1564,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1565,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1566,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1567,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1568,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1569,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1570,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1571,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1572,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1573,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1574,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1575,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1576,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1577,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1578,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1579,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1580,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1581,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1582,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1583,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1584,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1585,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1586,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1587,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1588,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1589,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1590,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1591,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1592,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1593,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1594,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1595,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1596,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1597,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1598,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1599,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1600,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1601,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1602,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1603,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1604,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1605,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1606,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1607,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1608,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1609,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1610,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1611,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1612,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1613,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1614,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1615,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1616,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1617,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1618,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1619,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1620,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1621,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1622,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1623,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1624,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1625,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1626,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1627,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1628,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1629,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1630,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1631,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1632,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1633,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1634,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1635,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1636,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1637,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1638,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1639,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1640,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1641,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1642,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1643,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1644,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1645,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1646,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1647,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1648,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1649,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1650,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1651,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1652,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1653,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1654,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1655,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1656,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1657,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1658,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1659,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1660,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1661,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1662,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1663,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1664,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1665,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1666,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1667,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1668,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1669,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1670,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1671,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1672,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1673,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1674,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1675,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1676,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1677,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1678,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1679,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1680,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1681,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1682,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1683,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1684,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1685,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1686,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1687,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1688,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1689,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1690,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1691,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1692,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1693,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1694,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1695,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1696,"kind":"mcpp.event","schemaVersion":1,"total":1697} -{"event":"progress","finished":1697,"kind":"mcpp.event","schemaVersion":1,"total":1697} +{"configuration":{"fingerprint":"38fc4cae0272ddf9","hostPlatform":null,"outputDir":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9","platform":{"fields":{"carrier":{"source":"platform","value":"openkal-run@0.1.3"},"layers.c++-abi":{"source":"platform","value":"openkal-llvm-runtime@0.16.6"},"layers.c-abi":{"source":"platform","value":"openkal-musl@0.22.6"},"layers.compiler-runtime":{"source":"platform","value":"openkal-llvm-runtime@0.16.6"},"link.driver":{"source":"platform","value":"lld"},"link.exe":{"source":"platform","value":"{name}.oke"},"link.shared":{"source":"platform","value":"lib{name}.okso"},"link.start":{"source":"platform","value":"ok_main"},"runner":{"source":"platform","value":["okrun","{}"]},"toolchain":{"source":"platform","value":"llvm@23.1.3"},"tools.okld":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/0daa33111e083da8/bin/okld"},"tools.okrun":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/3e48df0058ef2949/bin/okrun"}},"hosted":false,"name":"openkal-platform","source":"built-in","version":"0.17.3"},"profile":"dev","triple":"aarch64-openkal"},"event":"plan","kind":"mcpp.event","schemaVersion":1} +{"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":5,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":6,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":7,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":8,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":9,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":10,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":11,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":12,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":13,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":14,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":15,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":16,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":17,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":18,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":19,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":20,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":21,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":22,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":23,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":24,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":25,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":26,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":27,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":28,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":29,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":30,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":31,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":32,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":33,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":34,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":35,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":36,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":37,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":38,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":39,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":40,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":41,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":42,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":43,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":44,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":45,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":46,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":47,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":48,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":49,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":50,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":51,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":52,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":53,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":54,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":55,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":56,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":57,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":58,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":59,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":60,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":61,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":62,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":63,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":64,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":65,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":66,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":67,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":68,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":69,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":70,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":71,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":72,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":73,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":74,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":75,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":76,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":77,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":78,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":79,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":80,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":81,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":82,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":83,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":84,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":85,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":86,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":87,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":88,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":89,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":90,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":91,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":92,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":93,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":94,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":95,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":96,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":97,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":98,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":99,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":100,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":101,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":102,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":103,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":104,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":105,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":106,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":107,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":108,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":109,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":110,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":111,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":112,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":113,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":114,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":115,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":116,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":117,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":118,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":119,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":120,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":121,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":122,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":123,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":124,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":125,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":126,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":127,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":128,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":129,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":130,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":131,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":132,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":133,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":134,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":135,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":136,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":137,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":138,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":139,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":140,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":141,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":142,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":143,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":144,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":145,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":146,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":147,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":148,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":149,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":150,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":151,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":152,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":153,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":154,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":155,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":156,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":157,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":158,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":159,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":160,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":161,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":162,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":163,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":164,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":165,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":166,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":167,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":168,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":169,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":170,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":171,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":172,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":173,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":174,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":175,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":176,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":177,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":178,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":179,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":180,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":181,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":182,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":183,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":184,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":185,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":186,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":187,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":188,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":189,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":190,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":191,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":192,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":193,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":194,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":195,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":196,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":197,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":198,"kind":"mcpp.event","schemaVersion":1,"total":198} +{"event":"progress","finished":1,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":2,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":3,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":4,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":5,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":6,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":7,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":8,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":9,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":10,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":11,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":12,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":13,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":14,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":15,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":16,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":17,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":18,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":19,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":20,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":21,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":22,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":23,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":24,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":25,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":26,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":27,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":28,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":29,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":30,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":31,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":32,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":33,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":34,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":35,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":36,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":37,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":38,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":39,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":40,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":41,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":42,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":43,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":44,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":45,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":46,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":47,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":48,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":49,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":50,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":51,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":52,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":53,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":54,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":55,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":56,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":57,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":58,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":59,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":60,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":61,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":62,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":63,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":64,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":65,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":66,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":67,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":68,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":69,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":70,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":71,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":72,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":73,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":74,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":75,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":76,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":77,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":78,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":79,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":80,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":81,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":82,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":83,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":84,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":85,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":86,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":87,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":88,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":89,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":90,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":91,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":92,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":93,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":94,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":95,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":96,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":97,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":98,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":99,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":100,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":101,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":102,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":103,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":104,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":105,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":106,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":107,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":108,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":109,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":110,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":111,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":112,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":113,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":114,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":115,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":116,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":117,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":118,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":119,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":120,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":121,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":122,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":123,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":124,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":125,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":126,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":127,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":128,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":129,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":130,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":131,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":132,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":133,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":134,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":135,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":136,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":137,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":138,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":139,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":140,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":141,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":142,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":143,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":144,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":145,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":146,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":147,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":148,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":149,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":150,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":151,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":152,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":153,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":154,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":155,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":156,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":157,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":158,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":159,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":160,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":161,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":162,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":163,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":164,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":165,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":166,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":167,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":168,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":169,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":170,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":171,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":172,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":173,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":174,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":175,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":176,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":177,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":178,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":179,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":180,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":181,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":182,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":183,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":184,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":185,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":186,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":187,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":188,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":189,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":190,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":191,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":192,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":193,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":194,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":195,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":196,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":197,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":198,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":199,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":200,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":201,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":202,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":203,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":204,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":205,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":206,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":207,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":208,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":209,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":210,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":211,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":212,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":213,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":214,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":215,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":216,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":217,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":218,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":219,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":220,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":221,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":222,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":223,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":224,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":225,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":226,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":227,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":228,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":229,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":230,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":231,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":232,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":233,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":234,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":235,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":236,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":237,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":238,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":239,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":240,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":241,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":242,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":243,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":244,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":245,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":246,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":247,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":248,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":249,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":250,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":251,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":252,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":253,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":254,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":255,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":256,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":257,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":258,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":259,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":260,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":261,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":262,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":263,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":264,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":265,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":266,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":267,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":268,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":269,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":270,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":271,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":272,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":273,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":274,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":275,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":276,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":277,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":278,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":279,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":280,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":281,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":282,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":283,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":284,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":285,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":286,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":287,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":288,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":289,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":290,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":291,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":292,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":293,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":294,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":295,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":296,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":297,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":298,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":299,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":300,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":301,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":302,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":303,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":304,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":305,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":306,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":307,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":308,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":309,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":310,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":311,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":312,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":313,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":314,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":315,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":316,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":317,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":318,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":319,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":320,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":321,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":322,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":323,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":324,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":325,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":326,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":327,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":328,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":329,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":330,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":331,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":332,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":333,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":334,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":335,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":336,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":337,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":338,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":339,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":340,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":341,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":342,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":343,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":344,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":345,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":346,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":347,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":348,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":349,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":350,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":351,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":352,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":353,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":354,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":355,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":356,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":357,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":358,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":359,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":360,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":361,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":362,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":363,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":364,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":365,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":366,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":367,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":368,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":369,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":370,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":371,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":372,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":373,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":374,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":375,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":376,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":377,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":378,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":379,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":380,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":381,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":382,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":383,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":384,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":385,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":386,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":387,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":388,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":389,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":390,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":391,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":392,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":393,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":394,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":395,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":396,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":397,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":398,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":399,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":400,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":401,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":402,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":403,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":404,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":405,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":406,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":407,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":408,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":409,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":410,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":411,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":412,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":413,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":414,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":415,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":416,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":417,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":418,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":419,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":420,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":421,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":422,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":423,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":424,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":425,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":426,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":427,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":428,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":429,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":430,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":431,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":432,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":433,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":434,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":435,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":436,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":437,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":438,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":439,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":440,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":441,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":442,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":443,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":444,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":445,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":446,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":447,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":448,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":449,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":450,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":451,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":452,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":453,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":454,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":455,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":456,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":457,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":458,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":459,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":460,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":461,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":462,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":463,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":464,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":465,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":466,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":467,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":468,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":469,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":470,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":471,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":472,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":473,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":474,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":475,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":476,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":477,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":478,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":479,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":480,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":481,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":482,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":483,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":484,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":485,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":486,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":487,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":488,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":489,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":490,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":491,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":492,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":493,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":494,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":495,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":496,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":497,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":498,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":499,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":500,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":501,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":502,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":503,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":504,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":505,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":506,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":507,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":508,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":509,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":510,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":511,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":512,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":513,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":514,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":515,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":516,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":517,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":518,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":519,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":520,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":521,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":522,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":523,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":524,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":525,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":526,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":527,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":528,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":529,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":530,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":531,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":532,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":533,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":534,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":535,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":536,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":537,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":538,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":539,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":540,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":541,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":542,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":543,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":544,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":545,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":546,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":547,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":548,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":549,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":550,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":551,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":552,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":553,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":554,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":555,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":556,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":557,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":558,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":559,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":560,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":561,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":562,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":563,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":564,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":565,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":566,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":567,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":568,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":569,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":570,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":571,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":572,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":573,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":574,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":575,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":576,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":577,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":578,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":579,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":580,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":581,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":582,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":583,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":584,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":585,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":586,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":587,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":588,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":589,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":590,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":591,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":592,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":593,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":594,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":595,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":596,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":597,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":598,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":599,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":600,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":601,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":602,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":603,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":604,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":605,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":606,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":607,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":608,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":609,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":610,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":611,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":612,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":613,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":614,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":615,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":616,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":617,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":618,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":619,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":620,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":621,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":622,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":623,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":624,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":625,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":626,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":627,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":628,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":629,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":630,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":631,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":632,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":633,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":634,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":635,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":636,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":637,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":638,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":639,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":640,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":641,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":642,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":643,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":644,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":645,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":646,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":647,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":648,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":649,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":650,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":651,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":652,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":653,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":654,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":655,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":656,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":657,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":658,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":659,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":660,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":661,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":662,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":663,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":664,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":665,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":666,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":667,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":668,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":669,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":670,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":671,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":672,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":673,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":674,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":675,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":676,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":677,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":678,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":679,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":680,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":681,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":682,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":683,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":684,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":685,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":686,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":687,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":688,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":689,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":690,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":691,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":692,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":693,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":694,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":695,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":696,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":697,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":698,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":699,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":700,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":701,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":702,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":703,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":704,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":705,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":706,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":707,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":708,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":709,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":710,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":711,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":712,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":713,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":714,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":715,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":716,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":717,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":718,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":719,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":720,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":721,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":722,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":723,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":724,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":725,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":726,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":727,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":728,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":729,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":730,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":731,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":732,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":733,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":734,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":735,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":736,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":737,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":738,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":739,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":740,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":741,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":742,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":743,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":744,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":745,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":746,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":747,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":748,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":749,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":750,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":751,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":752,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":753,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":754,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":755,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":756,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":757,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":758,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":759,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":760,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":761,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":762,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":763,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":764,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":765,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":766,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":767,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":768,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":769,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":770,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":771,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":772,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":773,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":774,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":775,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":776,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":777,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":778,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":779,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":780,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":781,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":782,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":783,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":784,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":785,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":786,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":787,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":788,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":789,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":790,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":791,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":792,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":793,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":794,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":795,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":796,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":797,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":798,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":799,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":800,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":801,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":802,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":803,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":804,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":805,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":806,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":807,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":808,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":809,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":810,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":811,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":812,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":813,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":814,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":815,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":816,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":817,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":818,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":819,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":820,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":821,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":822,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":823,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":824,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":825,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":826,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":827,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":828,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":829,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":830,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":831,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":832,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":833,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":834,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":835,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":836,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":837,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":838,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":839,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":840,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":841,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":842,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":843,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":844,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":845,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":846,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":847,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":848,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":849,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":850,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":851,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":852,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":853,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":854,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":855,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":856,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":857,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":858,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":859,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":860,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":861,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":862,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":863,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":864,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":865,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":866,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":867,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":868,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":869,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":870,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":871,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":872,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":873,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":874,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":875,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":876,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":877,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":878,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":879,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":880,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":881,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":882,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":883,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":884,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":885,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":886,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":887,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":888,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":889,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":890,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":891,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":892,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":893,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":894,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":895,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":896,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":897,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":898,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":899,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":900,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":901,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":902,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":903,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":904,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":905,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":906,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":907,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":908,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":909,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":910,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":911,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":912,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":913,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":914,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":915,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":916,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":917,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":918,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":919,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":920,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":921,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":922,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":923,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":924,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":925,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":926,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":927,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":928,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":929,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":930,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":931,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":932,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":933,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":934,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":935,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":936,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":937,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":938,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":939,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":940,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":941,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":942,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":943,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":944,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":945,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":946,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":947,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":948,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":949,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":950,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":951,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":952,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":953,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":954,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":955,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":956,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":957,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":958,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":959,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":960,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":961,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":962,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":963,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":964,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":965,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":966,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":967,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":968,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":969,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":970,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":971,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":972,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":973,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":974,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":975,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":976,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":977,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":978,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":979,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":980,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":981,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":982,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":983,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":984,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":985,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":986,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":987,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":988,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":989,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":990,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":991,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":992,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":993,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":994,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":995,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":996,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":997,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":998,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":999,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1000,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1001,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1002,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1003,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1004,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1005,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1006,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1007,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1008,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1009,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1010,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1011,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1012,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1013,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1014,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1015,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1016,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1017,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1018,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1019,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1020,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1021,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1022,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1023,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1024,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1025,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1026,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1027,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1028,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1029,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1030,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1031,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1032,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1033,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1034,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1035,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1036,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1037,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1038,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1039,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1040,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1041,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1042,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1043,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1044,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1045,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1046,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1047,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1048,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1049,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1050,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1051,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1052,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1053,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1054,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1055,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1056,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1057,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1058,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1059,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1060,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1061,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1062,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1063,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1064,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1065,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1066,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1067,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1068,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1069,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1070,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1071,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1072,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1073,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1074,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1075,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1076,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1077,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1078,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1079,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1080,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1081,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1082,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1083,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1084,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1085,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1086,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1087,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1088,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1089,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1090,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1091,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1092,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1093,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1094,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1095,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1096,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1097,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1098,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1099,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1100,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1101,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1102,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1103,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1104,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1105,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1106,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1107,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1108,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1109,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1110,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1111,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1112,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1113,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1114,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1115,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1116,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1117,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1118,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1119,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1120,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1121,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1122,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1123,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1124,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1125,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1126,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1127,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1128,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1129,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1130,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1131,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1132,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1133,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1134,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1135,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1136,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1137,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1138,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1139,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1140,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1141,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1142,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1143,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1144,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1145,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1146,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1147,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1148,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1149,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1150,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1151,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1152,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1153,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1154,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1155,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1156,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1157,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1158,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1159,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1160,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1161,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1162,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1163,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1164,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1165,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1166,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1167,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1168,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1169,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1170,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1171,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1172,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1173,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1174,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1175,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1176,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1177,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1178,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1179,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1180,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1181,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1182,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1183,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1184,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1185,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1186,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1187,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1188,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1189,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1190,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1191,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1192,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1193,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1194,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1195,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1196,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1197,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1198,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1199,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1200,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1201,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1202,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1203,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1204,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1205,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1206,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1207,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1208,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1209,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1210,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1211,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1212,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1213,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1214,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1215,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1216,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1217,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1218,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1219,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1220,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1221,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1222,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1223,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1224,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1225,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1226,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1227,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1228,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1229,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1230,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1231,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1232,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1233,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1234,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1235,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1236,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1237,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1238,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1239,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1240,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1241,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1242,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1243,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1244,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1245,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1246,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1247,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1248,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1249,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1250,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1251,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1252,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1253,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1254,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1255,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1256,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1257,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1258,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1259,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1260,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1261,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1262,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1263,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1264,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1265,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1266,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1267,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1268,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1269,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1270,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1271,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1272,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1273,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1274,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1275,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1276,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1277,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1278,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1279,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1280,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1281,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1282,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1283,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1284,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1285,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1286,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1287,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1288,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1289,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1290,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1291,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1292,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1293,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1294,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1295,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1296,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1297,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1298,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1299,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1300,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1301,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1302,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1303,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1304,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1305,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1306,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1307,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1308,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1309,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1310,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1311,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1312,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1313,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1314,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1315,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1316,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1317,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1318,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1319,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1320,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1321,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1322,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1323,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1324,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1325,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1326,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1327,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1328,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1329,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1330,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1331,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1332,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1333,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1334,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1335,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1336,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1337,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1338,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1339,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1340,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1341,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1342,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1343,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1344,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1345,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1346,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1347,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1348,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1349,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1350,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1351,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1352,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1353,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1354,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1355,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1356,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1357,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1358,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1359,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1360,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1361,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1362,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1363,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1364,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1365,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1366,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1367,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1368,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1369,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1370,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1371,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1372,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1373,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1374,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1375,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1376,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1377,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1378,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1379,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1380,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1381,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1382,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1383,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1384,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1385,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1386,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1387,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1388,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1389,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1390,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1391,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1392,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1393,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1394,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1395,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1396,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1397,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1398,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1399,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1400,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1401,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1402,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1403,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1404,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1405,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1406,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1407,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1408,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1409,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1410,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1411,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1412,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1413,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1414,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1415,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1416,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1417,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1418,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1419,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1420,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1421,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1422,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1423,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1424,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1425,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1426,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1427,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1428,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1429,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1430,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1431,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1432,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1433,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1434,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1435,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1436,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1437,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1438,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1439,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1440,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1441,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1442,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1443,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1444,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1445,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1446,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1447,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1448,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1449,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1450,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1451,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1452,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1453,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1454,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1455,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1456,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1457,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1458,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1459,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1460,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1461,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1462,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1463,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1464,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1465,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1466,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1467,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1468,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1469,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1470,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1471,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1472,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1473,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1474,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1475,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1476,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1477,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1478,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1479,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1480,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1481,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1482,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1483,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1484,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1485,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1486,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1487,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1488,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1489,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1490,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1491,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1492,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1493,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1494,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1495,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1496,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1497,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1498,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1499,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1500,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1501,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1502,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1503,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1504,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1505,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1506,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1507,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1508,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1509,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1510,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1511,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1512,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1513,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1514,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1515,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1516,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1517,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1518,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1519,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1520,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1521,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1522,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1523,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1524,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1525,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1526,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1527,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1528,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1529,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1530,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1531,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1532,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1533,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1534,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1535,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1536,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1537,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1538,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1539,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1540,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1541,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1542,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1543,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1544,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1545,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1546,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1547,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1548,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1549,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1550,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1551,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1552,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1553,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1554,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1555,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1556,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1557,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1558,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1559,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1560,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1561,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1562,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1563,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1564,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1565,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1566,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1567,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1568,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1569,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1570,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1571,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1572,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1573,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1574,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1575,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1576,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1577,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1578,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1579,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1580,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1581,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1582,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1583,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1584,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1585,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1586,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1587,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1588,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1589,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1590,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1591,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1592,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1593,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1594,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1595,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1596,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1597,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1598,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1599,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1600,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1601,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1602,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1603,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1604,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1605,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1606,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1607,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1608,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1609,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1610,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1611,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1612,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1613,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1614,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1615,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1616,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1617,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1618,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1619,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1620,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1621,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1622,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1623,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1624,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1625,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1626,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1627,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1628,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1629,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1630,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1631,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1632,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1633,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1634,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1635,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1636,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1637,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1638,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1639,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1640,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1641,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1642,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1643,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1644,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1645,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1646,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1647,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1648,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1649,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1650,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1651,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1652,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1653,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1654,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1655,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1656,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1657,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1658,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1659,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1660,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1661,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1662,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1663,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1664,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1665,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1666,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1667,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1668,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1669,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1670,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1671,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1672,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1673,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1674,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1675,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1676,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1677,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1678,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1679,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1680,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1681,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1682,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1683,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1684,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1685,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1686,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1687,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1688,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1689,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1690,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1691,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1692,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1693,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1694,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1695,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1696,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1697,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1698,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1699,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1700,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1701,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1702,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1703,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1704,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1705,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1706,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1707,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1708,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1709,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1710,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1711,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1712,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1713,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1714,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1715,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1716,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1717,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1718,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1719,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1720,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1721,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1722,"kind":"mcpp.event","schemaVersion":1,"total":1723} +{"event":"progress","finished":1723,"kind":"mcpp.event","schemaVersion":1,"total":1723} {"artifact":{"kind":"bin","launch":{"argv":[],"cwd":"@ROOT@","env":{},"via":"runner"},"name":"app","path":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9/bin/app.oke"},"event":"artifact","kind":"mcpp.event","schemaVersion":1} -{"data":{"artifacts":[{"kind":"bin","launch":{"argv":[],"cwd":"@ROOT@","env":{},"via":"runner"},"name":"app","path":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9/bin/app.oke"}],"client":"mcpp-ide-fixtures","command":"mcpp build --target aarch64-openkal --message-format json","compileDatabase":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9/compile_commands.json","configuration":{"fingerprint":"38fc4cae0272ddf9","hostPlatform":null,"outputDir":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9","platform":{"fields":{"carrier":{"source":"platform","value":"openkal-run@0.1.3"},"layers.c++-abi":{"source":"platform","value":"openkal-llvm-runtime@0.16.5"},"layers.c-abi":{"source":"platform","value":"openkal-musl@0.22.5"},"layers.compiler-runtime":{"source":"platform","value":"openkal-llvm-runtime@0.16.5"},"link.driver":{"source":"platform","value":"lld"},"link.exe":{"source":"platform","value":"{name}.oke"},"link.shared":{"source":"platform","value":"lib{name}.okso"},"link.start":{"source":"platform","value":"ok_main"},"runner":{"source":"platform","value":["okrun","{}"]},"toolchain":{"source":"platform","value":"llvm@23.1.3"},"tools.okld":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/0daa33111e083da8/bin/okld"},"tools.okrun":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/3e48df0058ef2949/bin/okrun"}},"hosted":false,"name":"openkal-platform","source":"built-in","version":"0.17.2"},"profile":"dev","triple":"aarch64-openkal"},"diagnostics":[],"finishedAt":1793148661130,"pid":1204344,"startedAt":1793148653933,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} +{"data":{"artifacts":[{"kind":"bin","launch":{"argv":[],"cwd":"@ROOT@","env":{},"via":"runner"},"name":"app","path":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9/bin/app.oke"}],"client":"mcpp-ide-fixtures","command":"mcpp build --target aarch64-openkal --message-format json","compileDatabase":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9/compile_commands.json","configuration":{"fingerprint":"38fc4cae0272ddf9","hostPlatform":null,"outputDir":"@ROOT@/target/aarch64-openkal/38fc4cae0272ddf9","platform":{"fields":{"carrier":{"source":"platform","value":"openkal-run@0.1.3"},"layers.c++-abi":{"source":"platform","value":"openkal-llvm-runtime@0.16.6"},"layers.c-abi":{"source":"platform","value":"openkal-musl@0.22.6"},"layers.compiler-runtime":{"source":"platform","value":"openkal-llvm-runtime@0.16.6"},"link.driver":{"source":"platform","value":"lld"},"link.exe":{"source":"platform","value":"{name}.oke"},"link.shared":{"source":"platform","value":"lib{name}.okso"},"link.start":{"source":"platform","value":"ok_main"},"runner":{"source":"platform","value":["okrun","{}"]},"toolchain":{"source":"platform","value":"llvm@23.1.3"},"tools.okld":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/0daa33111e083da8/bin/okld"},"tools.okrun":{"source":"platform","value":"@HOME@/.mcpp/build-cache/v1/tool/mcpplibs/openkal-tools@0.1.3/3e48df0058ef2949/bin/okrun"}},"hosted":false,"name":"openkal-platform","source":"built-in","version":"0.17.3"},"profile":"dev","triple":"aarch64-openkal"},"diagnostics":[],"finishedAt":1793166359161,"pid":3248420,"startedAt":1793166353675,"status":"ok"},"diagnostics":[],"effects":["read-project","write-project"],"kind":"mcpp.build","kindVersion":1,"mcpp":{"protocol":{"max":1,"min":1},"version":"2026.10.27.1"},"schemaVersion":1} diff --git a/protocol/fixtures/cache-list.json b/protocol/fixtures/cache-list.json index 8b93fbd..c1dc08d 100644 --- a/protocol/fixtures/cache-list.json +++ b/protocol/fixtures/cache-list.json @@ -2,7 +2,7 @@ "data": { "entries": [ { - "accessed": 1793135706, + "accessed": 1793152617, "bytes": 2808, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/26916f34b8cd3aed", @@ -12,7 +12,7 @@ "label": "local-dev/local-dev.gfx-runtime@1.0.0" }, { - "accessed": 1793135706, + "accessed": 1793152616, "bytes": 4688, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/27e4d0283d6e95aa", @@ -22,7 +22,7 @@ "label": "local-dev/local-dev.gfx-runtime@1.0.0" }, { - "accessed": 1793135706, + "accessed": 1793152617, "bytes": 2792, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/local-dev/local-dev.gfx-runtime@1.0.0/07829ab3ec4688f8", @@ -42,7 +42,7 @@ "label": "compat/compat.mbedtls@3.6.1" }, { - "accessed": 1793148437, + "accessed": 1793152071, "bytes": 4165240, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.mbedtls@3.6.1/40557c641c314332", @@ -62,7 +62,7 @@ "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1793146687, + "accessed": 1793153192, "bytes": 2952, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xorgproto@2025.1/57a40b9605feaaee", @@ -72,7 +72,7 @@ "label": "compat/compat.xorgproto@2025.1" }, { - "accessed": 1793146687, + "accessed": 1793153192, "bytes": 558088, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb@1.17.0/c1bb7e4064dba71b", @@ -102,7 +102,7 @@ "label": "compat/compat.xext@1.3.7" }, { - "accessed": 1793146687, + "accessed": 1793153192, "bytes": 935896, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xext@1.3.7/86e10bc0a9eb4db6", @@ -112,7 +112,7 @@ "label": "compat/compat.xext@1.3.7" }, { - "accessed": 1793148082, + "accessed": 1793166108, "bytes": 736888, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.zstd@1.5.7/b3371f11886433a0", @@ -122,7 +122,7 @@ "label": "compat/compat.zstd@1.5.7" }, { - "accessed": 1793147496, + "accessed": 1793163908, "bytes": 737456, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.zstd@1.5.7/1bc50801f90769da", @@ -132,7 +132,7 @@ "label": "compat/compat.zstd@1.5.7" }, { - "accessed": 1793148437, + "accessed": 1793152071, "bytes": 4267480, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.zstd@1.5.7/3e322a18ff50d93f", @@ -141,6 +141,16 @@ "kind": "pkg", "label": "compat/compat.zstd@1.5.7" }, + { + "accessed": 1793166326, + "bytes": 737456, + "complete": true, + "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.zstd@1.5.7/446eea6f62eb7a6f", + "files": 27, + "key": "446eea6f62eb7a6f", + "kind": "pkg", + "label": "compat/compat.zstd@1.5.7" + }, { "accessed": 1793132038, "bytes": 4267480, @@ -152,7 +162,7 @@ "label": "compat/compat.zstd@1.5.7" }, { - "accessed": 1793148628, + "accessed": 1793155305, "bytes": 3458384, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.freetype@2.13.3/32588b37a58c1fdf", @@ -182,7 +192,7 @@ "label": "compat/compat.freetype@2.13.3" }, { - "accessed": 1793145509, + "accessed": 1793158637, "bytes": 925584, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.gtest@1.15.2/2acd640e7d91e5bd", @@ -202,7 +212,7 @@ "label": "compat/compat.x11@1.8.13" }, { - "accessed": 1793146687, + "accessed": 1793153192, "bytes": 21818960, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.x11@1.8.13/cb343939501cb4ce", @@ -222,7 +232,7 @@ "label": "compat/compat.bzip2@1.0.8" }, { - "accessed": 1793148437, + "accessed": 1793152071, "bytes": 188464, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.bzip2@1.0.8/bb26e20da52e1540", @@ -242,7 +252,7 @@ "label": "compat/compat.xtrans@1.6.0" }, { - "accessed": 1793146687, + "accessed": 1793153192, "bytes": 2944, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xtrans@1.6.0/cc8eefe29166f0d1", @@ -252,7 +262,7 @@ "label": "compat/compat.xtrans@1.6.0" }, { - "accessed": 1793146687, + "accessed": 1793153192, "bytes": 2911064, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xi@1.8.3/44574f0fb23f9cb7", @@ -272,7 +282,7 @@ "label": "compat/compat.xi@1.8.3" }, { - "accessed": 1793148628, + "accessed": 1793155305, "bytes": 2960, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.concurrentqueue@1.0.5/34eab8a84521d53d", @@ -322,7 +332,7 @@ "label": "compat/compat.concurrentqueue@1.0.5" }, { - "accessed": 1793146687, + "accessed": 1793153192, "bytes": 600504, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xrandr@1.5.5/380ade378dbdd108", @@ -352,7 +362,7 @@ "label": "compat/compat.xcb-proto@1.17.0" }, { - "accessed": 1793146687, + "accessed": 1793153193, "bytes": 2944, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xcb-proto@1.17.0/d8f80c93fb43d75d", @@ -372,7 +382,7 @@ "label": "compat/compat.libpng@1.6.43" }, { - "accessed": 1793148628, + "accessed": 1793155305, "bytes": 800112, "complete": true, "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.libpng@1.6.43/9d5fda8f3e1cf7e9", @@ -390,16 +400,6 @@ "key": "8b37498564545e91", "kind": "pkg", "label": "compat/compat.libpng@1.6.43" - }, - { - "accessed": 1793140254, - "bytes": 60576, - "complete": true, - "dir": "@HOME@/.mcpp/build-cache/v1/pkg/compat/compat.xrender@0.9.12/6d16c726588807b8", - "files": 14, - "key": "6d16c726588807b8", - "kind": "pkg", - "label": "compat/compat.xrender@0.9.12" } ], "root": "@HOME@/.mcpp/build-cache/v1" diff --git a/protocol/fixtures/result-ok.json b/protocol/fixtures/result-ok.json index 17d2b02..b7288cd 100644 --- a/protocol/fixtures/result-ok.json +++ b/protocol/fixtures/result-ok.json @@ -32,9 +32,9 @@ "triple": "x86_64-linux-gnu" }, "diagnostics": [], - "finishedAt": 1793148650353, - "pid": 1203929, - "startedAt": 1793148649554, + "finishedAt": 1793166350218, + "pid": 3248166, + "startedAt": 1793166349536, "status": "ok" }, "kind": "mcpp.result", diff --git a/protocol/fixtures/test.ndjson b/protocol/fixtures/test.ndjson index 11bf575..d2299c0 100644 --- a/protocol/fixtures/test.ndjson +++ b/protocol/fixtures/test.ndjson @@ -1,2 +1,2 @@ -{"member":"","test":"test_smoke","status":"pass","exit_code":0,"signal":null,"duration_ms":3,"timed_out":false,"compile_output":"","run_output":"test_smoke: ok\n","reason":"","build_ms":680} -{"summary":{"member":"","passed":1,"failed":0,"not_run":0,"not_run_reason":"","built":0,"elapsed_ms":943,"build_ms":741,"run_ms":3}} +{"member":"","test":"test_smoke","status":"pass","exit_code":0,"signal":null,"duration_ms":2,"timed_out":false,"compile_output":"","run_output":"test_smoke: ok\n","reason":"","build_ms":587} +{"summary":{"member":"","passed":1,"failed":0,"not_run":0,"not_run_reason":"","built":0,"elapsed_ms":792,"build_ms":614,"run_ms":2}} diff --git a/protocol/fixtures/toolchain-list-platform.json b/protocol/fixtures/toolchain-list-platform.json index 693c278..d5a505a 100644 --- a/protocol/fixtures/toolchain-list-platform.json +++ b/protocol/fixtures/toolchain-list-platform.json @@ -105,7 +105,7 @@ "default": false, "note": "ok, static, cross", "pin": "llvm@23.1.3", - "platform": "mcpplibs.openkal-platform@0.17.2", + "platform": "mcpplibs.openkal-platform@0.17.3", "status": "available", "target": "aarch64-openkal", "toolchain": "llvm 23.1.3" @@ -240,7 +240,7 @@ "default": false, "note": "ok, static, cross", "pin": "llvm@23.1.3", - "platform": "mcpplibs.openkal-platform@0.17.2", + "platform": "mcpplibs.openkal-platform@0.17.3", "status": "available", "target": "x86_64-openkal", "toolchain": "llvm 23.1.3" diff --git a/protocol/fixtures/toolchain-list.json b/protocol/fixtures/toolchain-list.json index 693c278..d5a505a 100644 --- a/protocol/fixtures/toolchain-list.json +++ b/protocol/fixtures/toolchain-list.json @@ -105,7 +105,7 @@ "default": false, "note": "ok, static, cross", "pin": "llvm@23.1.3", - "platform": "mcpplibs.openkal-platform@0.17.2", + "platform": "mcpplibs.openkal-platform@0.17.3", "status": "available", "target": "aarch64-openkal", "toolchain": "llvm 23.1.3" @@ -240,7 +240,7 @@ "default": false, "note": "ok, static, cross", "pin": "llvm@23.1.3", - "platform": "mcpplibs.openkal-platform@0.17.2", + "platform": "mcpplibs.openkal-platform@0.17.3", "status": "available", "target": "x86_64-openkal", "toolchain": "llvm 23.1.3" diff --git a/protocol/mcpp-contract.schema.json b/protocol/mcpp-contract.schema.json index f83f435..093e221 100644 --- a/protocol/mcpp-contract.schema.json +++ b/protocol/mcpp-contract.schema.json @@ -243,7 +243,7 @@ "default": { "type": "boolean" }, "note": { "type": "string" }, "platform": { - "description": "The platform the target table selects for the row, as a package spec (`mcpplibs.openkal-platform@0.17.2`); null for a row with none (mcpp SPEC-013).", + "description": "The platform the target table selects for the row, as a package spec (`mcpplibs.openkal-platform@0.17.3`); null for a row with none (mcpp SPEC-013).", "type": ["string", "null"] } } From fefc800b10a925e47ce7822fe123be975a92486d Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 14:49:02 +0900 Subject: [PATCH 27/30] CI: the bundle and the universal package are packed once, on Linux, with okrun for Linux, macOS and Windows (each built over the platform's hosted arrangement); no per-system packs and no --merge Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/workflows/ci.yml | 95 +++++++++++----------------------------- docs/architecture.md | 8 ++-- 2 files changed, 29 insertions(+), 74 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f7faf72..ed5c7b9 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,14 +17,12 @@ env: jobs: # The backend on each system the editors run on: build every program (the backend, the mock mcpp, # the dev tool), run the tests -- the protocol against its schema and the fixtures against mcpp's - # contract among them -- and check the translations. A `pack` leg then packs the backend as the - # editor packages carry it (mcpp design 2026-10-28 part 2 §15): its universal self-contained - # package (`<arch>-openkal`: the x86_64 and aarch64 images, okrun for the `systems` it names), and - # on linux-x64 the ok-image bundle. Windows' okrun is packed on Linux (x86_64-windows-gnu, static): - # an image built on Windows is not yet the same file as one built on Linux or macOS (its __FILE__ - # strings keep `\`), and `mcpp pack --merge` joins only packages that hold the same images. The - # `host-platform` row builds and tests with the build programs (build.mcpp, the spec/ generators) - # as ok images run by okrun. + # contract among them -- and check the translations. The `pack` leg then packs the backend as the + # editor packages carry it (mcpp design 2026-10-28 part 2 §15): the ok-image bundle, and the + # universal self-contained package (both images; okrun for Linux, macOS and Windows, each built + # over the platform's hosted arrangement) whose okrun the packages take. The `host-platform` row + # builds and tests with the build programs (build.mcpp, the spec/ generators) as ok images run by + # okrun. backend: name: backend (${{ matrix.platform }}${{ matrix.host-platform && format(', host platform {0}', matrix.host-platform) || '' }}) runs-on: ${{ matrix.os }} @@ -33,11 +31,11 @@ jobs: fail-fast: false matrix: include: - - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: 'package okb', systems: 'linux,windows' } - - { os: ubuntu-24.04-arm, platform: linux-arm64, llvm: 'false', pack: '' } - - { os: macos-14, platform: darwin-arm64, llvm: 'true', pack: 'package', systems: 'macos' } - - { os: windows-2022, platform: win32-x64, llvm: 'true', pack: '' } - - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: '', host-platform: 'openkal-platform@0.17.3' } + - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', pack: true } + - { os: ubuntu-24.04-arm, platform: linux-arm64, llvm: 'false' } + - { os: macos-14, platform: darwin-arm64, llvm: 'true' } + - { os: windows-2022, platform: win32-x64, llvm: 'true' } + - { os: ubuntu-24.04, platform: linux-x64, llvm: 'false', host-platform: 'openkal-platform@0.17.3' } defaults: run: shell: bash @@ -55,75 +53,32 @@ jobs: run: mcpp test - name: Every string has its translation run: mcpp run mcpp-ide-dev -- check-i18n - - name: The backend's packages - if: matrix.pack != '' + - name: The backend as the editor packages carry it + if: matrix.pack run: | set -euo pipefail version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" - case "$(uname -m)" in x86_64|amd64|AMD64) arch=x86_64 ;; *) arch=aarch64 ;; esac - case "$RUNNER_OS" in Linux) system=linux ;; *) system=macos ;; esac package="mcpp-ide-$version-openkal" - mkdir -p out unpacked - # An archive keeps the mode bits an artifact does not, and names its one directory. - mcpp pack mcpp-ide --target "$arch-openkal" --mode self-contained --systems "${{ matrix.systems }}" \ + mcpp pack mcpp-ide --target x86_64-openkal --mode self-contained --systems linux,macos,windows \ --pkg-format tar -o "$package.tar.gz" - cp "target/dist/$package.tar.gz" out/ - tar -xzf "out/$package.tar.gz" -C unpacked - ls -R "unpacked/$package/libexec" - "unpacked/$package/bin/mcpp-ide" --version - case " ${{ matrix.pack }} " in *" okb "*) - mcpp pack mcpp-ide --target "$arch-openkal" --pkg-format okb - cp "target/dist/mcpp-ide-$version.okb" out/mcpp-ide.okb - "unpacked/$package/libexec/okrun/$system-$arch/okrun" out/mcpp-ide.okb --version - ;; - esac - ls -l out - - uses: actions/upload-artifact@v5 - if: matrix.pack != '' - with: - name: backend-${{ matrix.platform }} - path: out - - # The packages of every system made one (`mcpp pack --merge`): the universal self-contained package - # (both images, okrun for every system a leg packed), and what the editor packages carry of it -- - # the bundle and the okrun of each system and architecture. - backend-package: - name: backend package - needs: backend - runs-on: ubuntu-24.04 - timeout-minutes: 30 - defaults: - run: - shell: bash - steps: - - uses: actions/checkout@v5 - - uses: ./.github/actions/setup-mcpp - - uses: actions/download-artifact@v5 - with: - pattern: backend-* - path: backends - - name: One package for every system - run: | - set -euo pipefail - version="$(sed -n 's/^version *= *"\(.*\)"/\1/p' mcpp.toml | head -1)" - package="mcpp-ide-$version-openkal" - mkdir -p merged backend - merge=() - for p in backends/*/"$package.tar.gz"; do merge+=(--merge "$p"); done - mcpp pack "${merge[@]}" -o "$PWD/backend/$package.tar.gz" - tar -xzf "backend/$package.tar.gz" -C merged - cp backends/backend-linux-x64/mcpp-ide.okb backend/mcpp-ide.okb - cp -R "merged/$package/libexec/okrun" backend/okrun - python3 - "merged/$package/mcpp-package.json" <<'PY' + mcpp pack mcpp-ide --target x86_64-openkal --pkg-format okb + mkdir -p backend unpacked + cp "target/dist/$package.tar.gz" backend/ + cp "target/dist/mcpp-ide-$version.okb" backend/mcpp-ide.okb + tar -xzf "backend/$package.tar.gz" -C unpacked + cp -R "unpacked/$package/libexec/okrun" backend/okrun + python3 - "unpacked/$package/mcpp-package.json" <<'PY' import json, sys d = json.load(open(sys.argv[1])) print("legs", d["legs"], "systems", d["systems"]) want = {"linux-x86_64", "linux-aarch64", "macos-aarch64", "windows-x86_64"} assert want <= set(d["systems"]), d["systems"] PY + "unpacked/$package/bin/mcpp-ide" --version backend/okrun/linux-x86_64/okrun backend/mcpp-ide.okb --version ls -lR backend - uses: actions/upload-artifact@v5 + if: matrix.pack with: name: backend path: backend @@ -133,7 +88,7 @@ jobs: # mock mcpp, with that backend and with the bundle it carries; then the package, and its file list. vscode: name: VS Code extension - needs: backend-package + needs: backend runs-on: ubuntu-24.04 timeout-minutes: 45 defaults: @@ -190,7 +145,7 @@ jobs: # (2025.2) and the one it is built on. jetbrains: name: CLion plugin - needs: backend-package + needs: backend runs-on: ubuntu-24.04 timeout-minutes: 90 defaults: diff --git a/docs/architecture.md b/docs/architecture.md index f8ac589..c27ac14 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -41,12 +41,12 @@ editor package carries that bundle and the runner that starts it on each system: | Layout in the package | Holds | Started as | |---|---|---| | `backend/mcpp-ide.okb` | the x86_64 and aarch64 images | | -| `backend/okrun/<os>-<arch>/okrun[.exe]` | okrun for `linux-x86_64`, `linux-aarch64`, `macos-aarch64`, `windows-x86_64`: the universal self-contained packages (`mcpp pack --mode self-contained`) packed on Linux (`--systems linux,windows`) and on macOS, joined by `mcpp pack --merge` | `okrun mcpp-ide.okb serve`: the okrun carried for this system, else okrun on PATH | +| `backend/okrun/<os>-<arch>/okrun[.exe]` | okrun for `linux-x86_64`, `linux-aarch64`, `macos-aarch64`, `windows-x86_64`, from the universal self-contained package (`mcpp pack --mode self-contained --systems linux,macos,windows`: each okrun built over the platform's hosted arrangement) | `okrun mcpp-ide.okb serve`: the okrun carried for this system, else okrun on PATH | Before it, a configured `mcpp.ide.backendPath` (a program or an `.okb`) is used; after it, an -installed `mcpp-ide` (xlings, whose command runs okrun on its bundle) or one on PATH. CI builds the -bundle once, joins the self-contained packages (`mcpp-ide-<version>-openkal.tar.gz`, a release asset), -takes okrun from the joined package, opens both editor packages and the joined package on every +installed `mcpp-ide` (xlings, whose command runs okrun on its bundle) or one on PATH. CI packs the +bundle and the universal package (`mcpp-ide-<version>-openkal.tar.gz`, a release asset) once, on +Linux, takes okrun from that package, opens both editor packages and the universal package on every system and starts what they carry for it (`.github/scripts/check-package.sh`). ## Generated declarations From 290d94d9d387ee8d14a476b7523030d3ee8fbdf4 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 23:15:27 +0900 Subject: [PATCH 28/30] spec: mcpp 2026.10.27.1's manifest keys and build-program directives; CI on the released mcpp spec/toml-schema.json is taken from mcpp 2026.10.27.1 (e0b1133d): [platform] and its tables (build and its cfg tables, carrier, hosted, layers, link, [[platform.link.inputs]], runners, tools, versions), [host] platform, the selector keys platform, carrier, requires, run_under and runners, [pack] linkage, format, compress, sign and universal, and [build] compile_commands. A platform's table is one section under [platform] and under the selector that overrides it (target.<sel>.link is platform.link). spec/buildscript-api.json is protocol 17: link-start, link-driver, link-input, artifact-name, seal and run-host, and each directive names the typed API's functions that emit it; build.mcpp completion offers those names (mcpp::link_driver, mcpp::define) rather than the wire's. CI installs mcpp 2026.10.27.1 and builds none from a ref; .xlings.json pins it. The views' comments name openkal-platform 0.17.3. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- .github/versions.env | 15 +- .xlings.json | 2 +- CHANGELOG.md | 4 + spec/buildscript-api.json | 182 ++++++++++++++++- spec/toml-schema.json | 419 +++++++++++++++++++++++++++++++++++++- src/manifest.cppm | 52 ++++- src/views.cppm | 4 +- tests/test_manifest.cpp | 32 +++ 8 files changed, 685 insertions(+), 25 deletions(-) diff --git a/.github/versions.env b/.github/versions.env index 756b43b..614779f 100644 --- a/.github/versions.env +++ b/.github/versions.env @@ -1,13 +1,14 @@ # The versions CI builds and tests with, in one file; .github/actions/setup-mcpp exports them. -# The released mcpp CI installs; with MCPP_SOURCE_REF, the one that builds mcpp from that ref. -MCPP_VERSION=2026.10.26.2 -# Until mcpp 2026.10.27.1 is released: the ref of mcpp-community/mcpp CI builds and uses, whose control -# contract the fixtures were captured from (protocol/fixtures/version.txt) and whose platforms -# (openkal-platform 0.17.3) the backend's ok images are built on. Empty: the release above is used. -MCPP_SOURCE_REF=release/2026.10.27.1 +# The released mcpp CI installs and uses: the control contract the fixtures were captured from +# (protocol/fixtures/version.txt) and the platforms (openkal-platform 0.17.3) the backend's ok images +# are built on. +MCPP_VERSION=2026.10.27.1 +# A ref of mcpp-community/mcpp CI builds mcpp from and uses instead, for a contract not yet released. +# Empty: the release above is used. +MCPP_SOURCE_REF= # The LLVM the backend builds with on macOS and Windows (the targets mcpp reaches there with it). LLVM_VERSION=23.1.3 -# The xlings mcpp 2026.10.26.2 bundles, which reads the current index. +# The xlings mcpp 2026.10.27.1 bundles, which reads the current index. XLINGS_VERSION=v2026.10.26.1 # The oldest VS Code the extension supports (engines.vscode), which its tests run in. VSCODE_VERSION=1.91.0 diff --git a/.xlings.json b/.xlings.json index 56b60cc..8eff4f4 100644 --- a/.xlings.json +++ b/.xlings.json @@ -1,5 +1,5 @@ { "workspace": { - "mcpp": "2026.10.26.2" + "mcpp": "2026.10.27.1" } } diff --git a/CHANGELOG.md b/CHANGELOG.md index bd01839..331ea8c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,10 @@ The first release of mcpp-ide: one backend for mcpp's editor integrations, the V - Shared panels: project, targets and platforms, libraries, dependency and module graphs, cache, pack, settings. - VS Code: tasks, Testing view, debug configurations, Problems from mcpp, mcpp.toml editing help. +- mcpp.toml and build.mcpp editing help over mcpp 2026.10.27.1's keys and directives: `[platform]` + and its tables, `[host]`, a selector's platform overrides (`platform`, `carrier`, `layers`, + `tools`, `link`, `runners`, `run_under`), `[pack]`'s `linkage`, `format`, `compress`, `sign` and + `universal`; the protocol 17 directives, completed by the typed API's names (`mcpp::link_driver`). - CLion: run configurations with a PTY console, test tree, CLion's debugger, console links, the mcpp tool window; depends on the mcppls CLion plugin. - One package per editor for every system: the backend as one ok-image bundle (x86_64 and aarch64 diff --git a/spec/buildscript-api.json b/spec/buildscript-api.json index 9b2f89d..a2a5c6f 100644 --- a/spec/buildscript-api.json +++ b/spec/buildscript-api.json @@ -1,7 +1,7 @@ { - "sourceVersion": "2026.10.17.1", - "sourceCommit": "684a306bced037014da08b038412f57c203d0bc9", - "protocolVersion": 15, + "sourceVersion": "2026.10.27.1", + "sourceCommit": "e0b1133dd2912f539ee68a06724cb524e3531f46", + "protocolVersion": 17, "cacheEpoch": 3, "roles": [ "source", @@ -28,6 +28,9 @@ { "wire": "cxxflag", "tag": "cxxflag", + "functions": [ + "cxxflag" + ], "slot": "CxxFlags", "scope": "PackagePrivate", "transform": "Verbatim", @@ -41,6 +44,9 @@ { "wire": "cflag", "tag": "cflag", + "functions": [ + "cflag" + ], "slot": "CFlags", "scope": "PackagePrivate", "transform": "Verbatim", @@ -54,6 +60,9 @@ { "wire": "link-lib", "tag": "ldflag", + "functions": [ + "link_lib" + ], "slot": "LdFlags", "scope": "LinkGlobal", "transform": "LibFlag", @@ -67,6 +76,9 @@ { "wire": "link-search", "tag": "ldflag", + "functions": [ + "link_search" + ], "slot": "LdFlags", "scope": "LinkGlobal", "transform": "LibSearchPath", @@ -80,6 +92,9 @@ { "wire": "cfg", "tag": "define", + "functions": [ + "define" + ], "slot": "Defines", "scope": "PackagePrivate", "transform": "DefinePrefix", @@ -93,6 +108,9 @@ { "wire": "generated", "tag": "generated", + "functions": [ + "generated" + ], "slot": "Generated", "scope": "SourceSet", "transform": "Verbatim", @@ -108,6 +126,9 @@ { "wire": "source", "tag": "source", + "functions": [ + "source" + ], "slot": "Sources", "scope": "SourceSet", "transform": "Verbatim", @@ -126,6 +147,9 @@ { "wire": "runner", "tag": "runner", + "functions": [ + "runner" + ], "slot": "Runner", "scope": "RunGlobal", "transform": "Verbatim", @@ -137,6 +161,9 @@ { "wire": "runner-named", "tag": "runner-named", + "functions": [ + "runner" + ], "slot": "NamedRunner", "scope": "RunGlobal", "transform": "Verbatim", @@ -148,6 +175,9 @@ { "wire": "runner-longlived", "tag": "runner-longlived", + "functions": [ + "runner_longlived" + ], "slot": "RunnerLongLived", "scope": "RunGlobal", "transform": "Verbatim", @@ -159,6 +189,9 @@ { "wire": "run-exclusive", "tag": "run-exclusive", + "functions": [ + "run_exclusive" + ], "slot": "RunExclusive", "scope": "RunGlobal", "transform": "Verbatim", @@ -170,6 +203,9 @@ { "wire": "link-script", "tag": "ldflag", + "functions": [ + "link_script" + ], "slot": "LdFlags", "scope": "LinkGlobal", "transform": "LinkerScript", @@ -181,6 +217,9 @@ { "wire": "link-flag", "tag": "ldflag", + "functions": [ + "link_flag" + ], "slot": "LdFlags", "scope": "LinkGlobal", "transform": "Verbatim", @@ -194,6 +233,9 @@ { "wire": "include-dir", "tag": "include-dir", + "functions": [ + "include_dir" + ], "slot": "IncludeDirs", "scope": "PackagePrivate", "transform": "AbsPath", @@ -207,6 +249,9 @@ { "wire": "include-dir-after", "tag": "include-dir-after", + "functions": [ + "include_dir_after" + ], "slot": "IncludeDirsAfter", "scope": "PackagePrivate", "transform": "AbsPath", @@ -220,6 +265,9 @@ { "wire": "rerun-if-changed", "tag": "", + "functions": [ + "rerun_if_changed" + ], "slot": "RerunFiles", "scope": "RerunKey", "transform": "Verbatim", @@ -231,6 +279,9 @@ { "wire": "rerun-if-env-changed", "tag": "", + "functions": [ + "rerun_if_env_changed" + ], "slot": "RerunEnv", "scope": "RerunKey", "transform": "Verbatim", @@ -242,6 +293,9 @@ { "wire": "rerun-if-changed-glob", "tag": "", + "functions": [ + "rerun_if_changed_glob" + ], "slot": "RerunGlobs", "scope": "RerunKey", "transform": "Verbatim", @@ -253,6 +307,9 @@ { "wire": "warning", "tag": "warning", + "functions": [ + "warning" + ], "slot": "Warnings", "scope": "Advisory", "transform": "Verbatim", @@ -268,6 +325,9 @@ { "wire": "diagnostic", "tag": "diagnostic", + "functions": [ + "report" + ], "slot": "Diagnostics", "scope": "Advisory", "transform": "Verbatim", @@ -279,6 +339,7 @@ { "wire": "action", "tag": "action", + "functions": [], "slot": "Actions", "scope": "GraphNode", "transform": "Verbatim", @@ -306,6 +367,9 @@ { "wire": "fact", "tag": "fact", + "functions": [ + "fact" + ], "slot": "Facts", "scope": "Claim", "transform": "Verbatim", @@ -319,6 +383,9 @@ { "wire": "floor", "tag": "floor", + "functions": [ + "floor" + ], "slot": "Floors", "scope": "Claim", "transform": "Verbatim", @@ -332,6 +399,9 @@ { "wire": "pack-format", "tag": "pack-format", + "functions": [ + "provides_pack_format" + ], "slot": "PackFormats", "scope": "Claim", "transform": "Verbatim", @@ -343,6 +413,9 @@ { "wire": "windows-subsystem", "tag": "windows-subsystem", + "functions": [ + "windows_subsystem" + ], "slot": "WindowsSubsystem", "scope": "TargetLink", "transform": "Verbatim", @@ -354,6 +427,9 @@ { "wire": "windows-entry", "tag": "windows-entry", + "functions": [ + "windows_entry" + ], "slot": "WindowsEntry", "scope": "TargetLink", "transform": "Verbatim", @@ -365,6 +441,9 @@ { "wire": "deploy", "tag": "deploy", + "functions": [ + "deploy" + ], "slot": "Deploy", "scope": "LinkGlobal", "transform": "Deploy", @@ -381,6 +460,9 @@ { "wire": "runtime-search-dir", "tag": "runtime-search-dir", + "functions": [ + "runtime_search_dir" + ], "slot": "RuntimeSearchDir", "scope": "LinkGlobal", "transform": "AbsPath", @@ -394,6 +476,9 @@ { "wire": "decision", "tag": "decision", + "functions": [ + "decision" + ], "slot": "ToolDecisions", "scope": "Advisory", "transform": "Verbatim", @@ -408,6 +493,9 @@ { "wire": "xpkg-request", "tag": "xpkg-request", + "functions": [ + "xpkg_request" + ], "slot": "XpkgRequests", "scope": "Claim", "transform": "Verbatim", @@ -419,6 +507,9 @@ { "wire": "toolchain", "tag": "toolchain", + "functions": [ + "toolchain" + ], "slot": "ToolchainStatement", "scope": "Claim", "transform": "Verbatim", @@ -429,6 +520,91 @@ "R9.9" ], "docsUrl": null + }, + { + "wire": "link-start", + "tag": "link-start", + "functions": [ + "link_start" + ], + "slot": "LinkStart", + "scope": "LinkGlobal", + "transform": "Verbatim", + "mustExist": false, + "since": 16, + "rules": [], + "docsUrl": "https://github.com/mcpp-community/mcpp/blob/e0b1133dd2912f539ee68a06724cb524e3531f46/docs/30-build-mcpp.md#typed-api-import-mcpp-recommended" + }, + { + "wire": "link-driver", + "tag": "link-driver", + "functions": [ + "link_driver" + ], + "slot": "LinkDriver", + "scope": "LinkGlobal", + "transform": "Verbatim", + "mustExist": false, + "since": 17, + "rules": [], + "docsUrl": "https://github.com/mcpp-community/mcpp/blob/e0b1133dd2912f539ee68a06724cb524e3531f46/docs/30-build-mcpp.md#typed-api-import-mcpp-recommended" + }, + { + "wire": "link-input", + "tag": "link-input", + "functions": [ + "link_input", + "link_input_from" + ], + "slot": "LinkInputs", + "scope": "LinkGlobal", + "transform": "Verbatim", + "mustExist": false, + "since": 17, + "rules": [], + "docsUrl": "https://github.com/mcpp-community/mcpp/blob/e0b1133dd2912f539ee68a06724cb524e3531f46/docs/30-build-mcpp.md#typed-api-import-mcpp-recommended" + }, + { + "wire": "artifact-name", + "tag": "artifact-name", + "functions": [ + "artifact_name" + ], + "slot": "ArtifactNames", + "scope": "LinkGlobal", + "transform": "Verbatim", + "mustExist": false, + "since": 17, + "rules": [], + "docsUrl": "https://github.com/mcpp-community/mcpp/blob/e0b1133dd2912f539ee68a06724cb524e3531f46/docs/30-build-mcpp.md#typed-api-import-mcpp-recommended" + }, + { + "wire": "seal", + "tag": "seal", + "functions": [ + "seal" + ], + "slot": "Seal", + "scope": "LinkGlobal", + "transform": "Verbatim", + "mustExist": false, + "since": 17, + "rules": [], + "docsUrl": "https://github.com/mcpp-community/mcpp/blob/e0b1133dd2912f539ee68a06724cb524e3531f46/docs/30-build-mcpp.md#typed-api-import-mcpp-recommended" + }, + { + "wire": "run-host", + "tag": "run-host", + "functions": [ + "run_host" + ], + "slot": "RunHost", + "scope": "RunGlobal", + "transform": "Verbatim", + "mustExist": false, + "since": 17, + "rules": [], + "docsUrl": "https://github.com/mcpp-community/mcpp/blob/e0b1133dd2912f539ee68a06724cb524e3531f46/docs/30-build-mcpp.md#typed-api-import-mcpp-recommended" } ] } diff --git a/spec/toml-schema.json b/spec/toml-schema.json index 9b14c33..9f28c86 100644 --- a/spec/toml-schema.json +++ b/spec/toml-schema.json @@ -1,6 +1,6 @@ { - "sourceVersion": "2026.10.26.2", - "sourceCommit": "684a306bced037014da08b038412f57c203d0bc9", + "sourceVersion": "2026.10.27.1", + "sourceCommit": "e0b1133dd2912f539ee68a06724cb524e3531f46", "sections": [ { "header": "[build]", @@ -54,6 +54,12 @@ "key": "cflags", "type": "array" }, + { + "key": "compile_commands", + "type": "string", + "since": "2026.10.26.1", + "note": "where the project's compile database is published, a path relative to the project root" + }, { "key": "cxx_runtime", "type": "enum", @@ -251,6 +257,21 @@ "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#216-hooks--project-build-lifecycle-commands", "deprecatedBy": null }, + { + "header": "[host]", + "name": "host", + "plane": "condition", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#the-host-graphs-platform", + "deprecatedBy": null, + "keys": [ + { + "key": "platform", + "type": "string", + "since": "2026.10.27.1", + "note": "the platform of the host graph: build programs and the tools the build runs are built for its targets and started through its runner" + } + ] + }, { "header": "[indices]", "name": "indices", @@ -343,7 +364,7 @@ "header": "[pack]", "name": "pack", "plane": "unclassified", - "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/10-pack-and-release.md#configuration", "deprecatedBy": null, "keys": [ { @@ -352,6 +373,12 @@ "note": "table of fine-grained overrides", "unmodelled": true }, + { + "key": "compress", + "type": "string", + "since": "2026.10.27.1", + "note": "the default of --compress: zstd, gzip, xz or none, with an optional :<level>" + }, { "key": "debug_symbols", "type": "string" @@ -369,13 +396,41 @@ "key": "exclude", "type": "array" }, + { + "key": "format", + "type": "string", + "since": "2026.10.27.1", + "note": "the default of --pkg-format: tar, zip, dir, single-file, or a format a package provides" + }, { "key": "include", "type": "array" }, + { + "key": "linkage", + "type": "enum", + "values": [ + "static", + "shared" + ], + "since": "2026.10.27.1", + "note": "the default of --linkage" + }, + { + "key": "sign", + "type": "array", + "since": "2026.10.27.1", + "note": "an argv run on each program, image, library and loader before the container is written; {} is the file" + }, { "key": "strip", "type": "boolean" + }, + { + "key": "universal", + "type": "boolean", + "since": "2026.10.27.1", + "note": "false is --no-universal: a pack of a universal platform's target covers that target alone" } ] }, @@ -496,6 +551,332 @@ } ] }, + { + "header": "[platform]", + "name": "platform", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#what-a-platform-states", + "deprecatedBy": null, + "keys": [ + { + "key": "build", + "type": "table", + "since": "2026.10.27.1", + "note": "cflags, cxxflags, asmflags, ldflags, and cfg(...) tables of the same keys; usually [platform.build]" + }, + { + "key": "carrier", + "type": "table", + "since": "2026.10.27.1", + "note": "{ package, section, main }: the program mcpp pack builds of a loaded artifact for a system (all three required)" + }, + { + "key": "hosted", + "type": "table", + "since": "2026.10.27.1", + "note": "what a host triple takes when it selects the platform: targets, toolchain, layers" + }, + { + "key": "layers", + "type": "table", + "since": "2026.10.27.1", + "note": "<layer> = <package> | false for kernel-abi, c-abi, c++-abi, compiler-runtime; usually [platform.layers]" + }, + { + "key": "link", + "type": "table", + "since": "2026.10.27.1", + "note": "driver, flags, start, script, inputs, exe, shared, seal; usually [platform.link]" + }, + { + "key": "plugin", + "type": "enum", + "values": [ + "build.mcpp" + ], + "since": "2026.10.27.1", + "note": "the package's build program, run in the platform phase; no other value is accepted" + }, + { + "key": "runner", + "type": "array", + "since": "2026.10.27.1", + "note": "how mcpp run and mcpp test start an artifact: an argv with {} for the artifact, or { cmd, host = \"same-arch\" | \"any\", exclusive }" + }, + { + "key": "runners", + "type": "table", + "since": "2026.10.27.1", + "note": "named device actions, <name> = [argv]" + }, + { + "key": "sysroot", + "type": "string", + "since": "2026.10.27.1", + "note": "a prebuilt target base, or { path = \"<dir>\", provides = [...] } with path relative to the platform package" + }, + { + "key": "targets", + "type": "array", + "since": "2026.10.27.1", + "note": "the target triples the platform serves (required, non-empty)" + }, + { + "key": "toolchain", + "type": "string", + "since": "2026.10.27.1", + "note": "the toolchain the targets use, e.g. \"llvm@23.1.3\"" + }, + { + "key": "tools", + "type": "table", + "since": "2026.10.27.1", + "note": "<name> = <package> | { program = \"<name>\" }: programs built for this machine, or found; usually [platform.tools]" + }, + { + "key": "universal", + "type": "boolean", + "since": "2026.10.27.1", + "note": "true: a pack of any of the targets covers all of them in one package (SPEC-014)" + }, + { + "key": "versions", + "type": "table", + "since": "2026.10.27.1", + "note": "the version group: <package> = \"<version>\", one version of each package of a family" + } + ] + }, + { + "header": "[platform.build]", + "name": "platform.build", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#writing-a-platform-package", + "deprecatedBy": null, + "keys": [ + { + "key": "asmflags", + "type": "array", + "since": "2026.10.27.1" + }, + { + "key": "cflags", + "type": "array", + "since": "2026.10.27.1" + }, + { + "key": "cxxflags", + "type": "array", + "since": "2026.10.27.1" + }, + { + "key": "ldflags", + "type": "array", + "since": "2026.10.27.1" + } + ] + }, + { + "header": "[platform.carrier]", + "name": "platform.carrier", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#writing-a-platform-package", + "deprecatedBy": null, + "keys": [ + { + "key": "main", + "type": "string", + "since": "2026.10.27.1", + "note": "the program's entry source, relative to the file that states it" + }, + { + "key": "package", + "type": "string", + "since": "2026.10.27.1", + "note": "the package the program depends on; a package: \"<name>@<version>\", or a table with name and one of version, path, git" + }, + { + "key": "section", + "type": "string", + "since": "2026.10.27.1", + "note": "the section the carried bytes are placed in, e.g. \".oke\"" + } + ] + }, + { + "header": "[platform.hosted]", + "name": "platform.hosted", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#the-hosted-arrangement", + "deprecatedBy": null, + "keys": [ + { + "key": "layers", + "type": "table", + "since": "2026.10.27.1", + "note": "the layers a host triple takes, as [platform.layers]" + }, + { + "key": "targets", + "type": "array", + "since": "2026.10.27.1", + "note": "the host triples that may select the platform" + }, + { + "key": "toolchain", + "type": "string", + "since": "2026.10.27.1", + "note": "the toolchain a host triple uses" + } + ] + }, + { + "header": "[platform.layers]", + "name": "platform.layers", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#overriding-part-of-a-platform", + "deprecatedBy": null, + "keys": [ + { + "key": "\"c++-abi\"", + "type": "string", + "since": "2026.10.27.1", + "note": "a package: \"<name>@<version>\", or a table with name and one of version, path, git, or false: the layer is left out" + }, + { + "key": "c-abi", + "type": "string", + "since": "2026.10.27.1", + "note": "a package: \"<name>@<version>\", or a table with name and one of version, path, git, or false: the layer is left out" + }, + { + "key": "compiler-runtime", + "type": "string", + "since": "2026.10.27.1", + "note": "a package: \"<name>@<version>\", or a table with name and one of version, path, git, or false: the layer is left out" + }, + { + "key": "kernel-abi", + "type": "string", + "since": "2026.10.27.1", + "note": "a package: \"<name>@<version>\", or a table with name and one of version, path, git, or false: the layer is left out" + } + ] + }, + { + "header": "[platform.link]", + "name": "platform.link", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#writing-a-platform-package", + "deprecatedBy": null, + "keys": [ + { + "key": "driver", + "type": "enum", + "values": [ + "compiler", + "lld" + ], + "since": "2026.10.27.1", + "note": "\"compiler\": the compiler driver links; \"lld\": ld.lld itself links, with flags" + }, + { + "key": "exe", + "type": "string", + "since": "2026.10.27.1", + "note": "an executable's name: \"{name}<suffix>\", e.g. \"{name}.oke\"" + }, + { + "key": "flags", + "type": "array", + "since": "2026.10.27.1", + "note": "appended after the platform's when overridden" + }, + { + "key": "inputs", + "type": "array", + "since": "2026.10.27.1", + "note": "files the link takes: { file = \"...\" } or { from = [argv], as = \"<file>\" }; replaced whole when overridden", + "unmodelled": true + }, + { + "key": "script", + "type": "string", + "since": "2026.10.27.1", + "note": "a linker script, relative to the file that states it" + }, + { + "key": "seal", + "type": "array", + "since": "2026.10.27.1", + "note": "steps run on the linked file before it is published, each an argv with {} (and {needed}); replaced whole when overridden", + "unmodelled": true + }, + { + "key": "shared", + "type": "string", + "since": "2026.10.27.1", + "note": "a shared image's name, with {name} once, e.g. \"lib{name}.okso\"" + }, + { + "key": "start", + "type": "string", + "since": "2026.10.27.1", + "note": "the symbol an image is entered at" + } + ] + }, + { + "header": "[[platform.link.inputs]]", + "name": "platform.link.inputs", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#writing-a-platform-package", + "deprecatedBy": null, + "keys": [ + { + "key": "as", + "type": "string", + "since": "2026.10.27.1", + "note": "the file name the program's output is saved as (with from)" + }, + { + "key": "file", + "type": "string", + "since": "2026.10.27.1", + "note": "a file the link takes, relative to the file that states it" + }, + { + "key": "from", + "type": "array", + "since": "2026.10.27.1", + "note": "the argv of a program whose output the link takes (with as)" + } + ] + }, + { + "header": "[platform.runners]", + "name": "platform.runners", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#what-a-platform-states", + "deprecatedBy": null, + "openKeys": true + }, + { + "header": "[platform.tools]", + "name": "platform.tools", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#overriding-part-of-a-platform", + "deprecatedBy": null, + "openKeys": true + }, + { + "header": "[platform.versions]", + "name": "platform.versions", + "plane": "platform", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/35-platforms.md#the-version-group", + "deprecatedBy": null, + "openKeys": true + }, { "header": "[profile]", "name": "profile", @@ -596,6 +977,12 @@ "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#271-target--platform-conditional-dependencies--flags", "deprecatedBy": null, "keys": [ + { + "key": "carrier", + "type": "table", + "since": "2026.10.27.1", + "note": "{ package, section, main }: the program mcpp pack builds of a loaded artifact for a system (docs/35)" + }, { "key": "cxx_runtime", "type": "enum", @@ -617,10 +1004,34 @@ "key": "min_api_level", "type": "number" }, + { + "key": "platform", + "type": "string", + "since": "2026.10.27.1", + "note": "the platform of the selected targets: \"<name>@<version>\", { path = \"...\" }, { git = ... }, or \"none\"; not accepted under a cfg(platform = ...) selector" + }, + { + "key": "requires", + "type": "array", + "since": "2026.10.26.1", + "note": "the target-axis form of [package] requires, unioned in when the selector matches" + }, + { + "key": "run_under", + "type": "array", + "since": "2026.10.24.1", + "note": "an argv placed before the runner: what reaches the machine the artifact runs on" + }, { "key": "runner", "type": "array", - "note": "argv template for mcpp run/test on this target" + "note": "argv template for mcpp run/test on this target, or { cmd, host = \"same-arch\" | \"any\", exclusive } (2026.10.27.1+)" + }, + { + "key": "runners", + "type": "table", + "since": "2026.9.4.2", + "note": "named runners, <name> = [argv]; also written as [target.<selector>.runners]" }, { "key": "sysroot", diff --git a/src/manifest.cppm b/src/manifest.cppm index 10c44d9..55f2793 100644 --- a/src/manifest.cppm +++ b/src/manifest.cppm @@ -1,6 +1,6 @@ // Editing help for mcpp.toml and build.mcpp: completion, hover and an outline, // from mcpp's own key registry and build-program directives (the snapshots in -// spec/, regenerated from an mcpp checkout by tools/generate-schemas.py). +// spec/, each naming the mcpp release and commit it was taken from). // // THIS IS TEXT, NOT MEANING. The analysis below finds where the cursor is -- // which `[table]` it is under, whether it is on a key or after `=` -- in the @@ -30,7 +30,10 @@ struct Context { Context context_at(std::string_view text, int line, int character); // The schema section a table header reads as: `target.<sel>.build` is `build`, -// `dependencies.<ns>` is `dependencies`, `targets.<name>` is `targets`. +// `dependencies.<ns>` is `dependencies`, `targets.<name>` is `targets`; a +// platform's table is the same section under `[platform]` and under the +// selector that overrides it (`platform.link` and `target.<sel>.link` are +// `platform.link`). std::string section_of(std::string_view table); // {text, line, character} -> {items: [{label, kind, detail, documentation, insertText, range}]} @@ -145,14 +148,40 @@ std::string key_doc(const Json& section, const Json& key) { return doc; } +// The section of a platform's table, from the segments after `platform` or +// after a selector (SPEC-013 §1, §2): `layers` is `platform.layers`, a +// `cfg(...)` table of `build` is `platform.build`, the entries of +// `link.inputs` are `platform.link.inputs`, the layers a host triple takes are +// `platform.layers`. Empty for a table that is not one of a platform's. +std::string platform_table(std::span<const std::string> rest) { + static constexpr std::string_view kTables[] = {"build", "carrier", "hosted", "layers", + "link", "runners", "tools", "versions"}; + if (rest.empty() || std::ranges::find(kTables, rest[0]) == std::end(kTables)) return {}; + if (rest.size() >= 2 && rest[0] == "link" && rest[1] == "inputs") return "platform.link.inputs"; + if (rest.size() >= 2 && rest[0] == "hosted" && rest[1] == "layers") return "platform.layers"; + return "platform." + rest[0]; +} + } // namespace std::string section_of(std::string_view table) { auto seg = segments(table); if (seg.empty()) return {}; - // A `target.<selector>` table reads as the table after the selector. - if (seg[0] == "target" && seg.size() >= 3) return seg[2]; + // A `target.<selector>` table reads as the table after the selector, and a + // platform's table there as the platform's. + if (seg[0] == "target" && seg.size() >= 3) { + // The tables a selector overrides a platform with (`build` there is + // the project's `[build]`; `hosted` and `versions` are a platform's own). + static constexpr std::string_view kOverrides[] = {"carrier", "layers", "link", "runners", "tools"}; + if (std::ranges::find(kOverrides, seg[2]) != std::end(kOverrides)) + return platform_table(std::span(seg).subspan(2)); + return seg[2]; + } if (seg[0] == "target") return "target"; + if (seg[0] == "platform") { + auto p = platform_table(std::span(seg).subspan(1)); + return p.empty() ? std::string("platform") : p; + } if (seg[0] == "workspace" && seg.size() >= 2) return seg[1] == "package" ? "package" : seg[1]; return seg[0]; } @@ -348,14 +377,21 @@ Json buildscript_complete(const Json& p) { return Json{{"items", Json::array()}}; Json items = Json::array(); const auto range = range_json(line, static_cast<int>(scope + 6), col); + std::set<std::string> offered; for (const auto& d : api()["directives"]) { - const auto tag = d.value("tag", d.value("wire", "")); - if (!tag.starts_with(typed)) continue; + // The typed API's functions that emit the directive (`include-dir` is + // `mcpp::include_dir`, `cfg` is `mcpp::define`); `action` is the + // snippet below. + if (!d.contains("functions") || !d["functions"].is_array()) continue; std::string doc = std::format("`mcpp:{}=` · slot `{}` · scope `{}` · since protocol {}", d.value("wire", ""), d.value("slot", ""), d.value("scope", ""), d.value("since", 0)); if (d.contains("docsUrl") && d["docsUrl"].is_string()) doc += std::format("\n\n[docs]({})", d["docsUrl"].get<std::string>()); - items.push_back(Json{{"label", tag}, {"kind", "function"}, {"detail", std::format("mcpp:{}=", d.value("wire", ""))}, - {"documentation", doc}, {"insertText", tag + "(\"$1\")"}, {"snippet", true}, {"range", range}}); + for (const auto& f : d["functions"]) { + const auto name = f.get<std::string>(); + if (!name.starts_with(typed) || !offered.insert(name).second) continue; + items.push_back(Json{{"label", name}, {"kind", "function"}, {"detail", std::format("mcpp:{}=", d.value("wire", ""))}, + {"documentation", doc}, {"insertText", name + "(\"$1\")"}, {"snippet", true}, {"range", range}}); + } } if (std::string_view("action").starts_with(typed)) items.push_back(Json{{"label", "action"}, {"kind", "snippet"}, {"detail", "mcpp::action with id, role, inputs, outputs"}, diff --git a/src/views.cppm b/src/views.cppm index 73f7f50..574e4a0 100644 --- a/src/views.cppm +++ b/src/views.cppm @@ -10,7 +10,7 @@ // module_graph the same modules, who provides, who imports // project_summary the same and the result record targets, tests, artifacts, last build // targets `mcpp toolchain list --format json` one row per target: its toolchains, its platform -// platform_text a `platform` object of mcpp's "openkal-platform 0.17.1 (built-in)" +// platform_text a `platform` object of mcpp's "openkal-platform 0.17.3 (built-in)" // stream_record one record of a `--message-format json` stream, normalised export module mcppide.views; @@ -50,7 +50,7 @@ Json project_summary(const Json& buildDatabaseEnvelope, const Json& lastResult); // reports one (design 2026-10-28 §9), the platform that configures it. `selected` is the target the // adapter builds for ("" for the host). Json targets(const Json& toolchainListEnvelope, std::string_view selected); -// "openkal-platform 0.17.1 (built-in)", "host conventions (built-in)"; "" for null or a non-object. +// "openkal-platform 0.17.3 (built-in)", "host conventions (built-in)"; "" for null or a non-object. std::string platform_text(const Json& platform); // One record of a `--message-format json` stream (a build's events, a test's records), as the diff --git a/tests/test_manifest.cpp b/tests/test_manifest.cpp index 408e401..acb51da 100644 --- a/tests/test_manifest.cpp +++ b/tests/test_manifest.cpp @@ -18,6 +18,16 @@ int main() { CHECK(manifest::section_of("target.'cfg(os = \"linux\")'.build") == "build"); CHECK(manifest::section_of("dependencies.mcpplibs") == "dependencies"); CHECK(manifest::section_of("targets.app") == "targets"); + // A platform's tables, under [platform] and under the selector that overrides it. + CHECK(manifest::section_of("platform") == "platform"); + CHECK(manifest::section_of("platform.link") == "platform.link"); + CHECK(manifest::section_of("platform.link.inputs") == "platform.link.inputs"); + CHECK(manifest::section_of("platform.build.'cfg(arch = \"aarch64\")'") == "platform.build"); + CHECK(manifest::section_of("platform.hosted.layers") == "platform.layers"); + CHECK(manifest::section_of("target.'cfg(platform = \"openkal\")'.layers") == "platform.layers"); + CHECK(manifest::section_of("target.x86_64-openkal.link") == "platform.link"); + CHECK(manifest::section_of("target.x86_64-openkal.versions") == "versions"); + CHECK(manifest::section_of("tools.overrides") == "tools"); const std::string text = "[package]\nname = \"a\"\n\n[build]\nbmi_schedule = \"\"\n\n"; auto keys = labels(manifest::complete(Json{{"text", text}, {"line", 5}, {"character", 0}})); @@ -32,5 +42,27 @@ int main() { CHECK(syms.size() == 2 && syms[1]["name"] == "build" && syms[1]["children"].size() == 1); auto bs = labels(manifest::buildscript_complete(Json{{"text", "int main(){ mcpp::cxx"}, {"line", 0}, {"character", 21}})); CHECK(has(bs, "cxxflag")); + // The typed API's names, not the wire's (`mcpp:link-driver=` is `mcpp::link_driver`). + auto link = labels(manifest::buildscript_complete(Json{{"text", "int main(){ mcpp::link"}, {"line", 0}, {"character", 22}})); + CHECK(has(link, "link_driver") && has(link, "link_input_from") && has(link, "link_lib") && !has(link, "link-driver")); + auto def = labels(manifest::buildscript_complete(Json{{"text", "int main(){ mcpp::de"}, {"line", 0}, {"character", 20}})); + CHECK(has(def, "define") && has(def, "deploy")); + + // The platform keys of mcpp 2026.10.27.1. + const std::string plat = "[platform]\ntargets = []\n\n[platform.link]\n\n[target.x86_64-openkal]\n\n[host]\n\n[pack]\n"; + auto pk = labels(manifest::complete(Json{{"text", plat}, {"line", 2}, {"character", 0}})); + CHECK(has(pk, "universal") && has(pk, "plugin") && !has(pk, "targets")); + auto lk = labels(manifest::complete(Json{{"text", plat}, {"line", 4}, {"character", 0}})); + CHECK(has(lk, "driver") && has(lk, "seal") && has(lk, "exe")); + auto drv = labels(manifest::complete(Json{{"text", "[platform.link]\ndriver = \"\"\n"}, {"line", 1}, {"character", 10}})); + CHECK(has(drv, "lld") && has(drv, "compiler")); + auto tk = labels(manifest::complete(Json{{"text", plat}, {"line", 6}, {"character", 0}})); + CHECK(has(tk, "platform") && has(tk, "carrier") && has(tk, "run_under")); + auto hk = labels(manifest::complete(Json{{"text", plat}, {"line", 8}, {"character", 0}})); + CHECK(has(hk, "platform")); + auto pack = labels(manifest::complete(Json{{"text", plat}, {"line", 10}, {"character", 0}})); + CHECK(has(pack, "format") && has(pack, "compress") && has(pack, "universal") && has(pack, "sign")); + auto ph = labels(manifest::complete(Json{{"text", "[plat"}, {"line", 0}, {"character", 5}})); + CHECK(has(ph, "[platform]") && has(ph, "[platform.link]") && has(ph, "[[platform.link.inputs]]") && has(ph, "[host]")); std::println("test_manifest: ok"); } From 403c8edf5fcdcde6840a4132c722f45cafbc307c Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Wed, 28 Oct 2026 23:29:16 +0900 Subject: [PATCH 29/30] spec: every table and key mcpp 2026.10.27.1 reads, each with the release that added it The manifest reader of mcpp e0b1133d was read table by table (the get_* paths of toml.cppm, its known-key lists, key_registry.cppm) and the schema now holds what it lacked: [target.<selector>.abi], requires_abi (of [package], a feature, a selector; a table, not an array) and [target.<selector>.feature-requires-abi]; [c-abi], [kernel-abi], [scan_overrides] and [workspace] keys; [runtime]'s keys and its [[runtime.requirements]], [[runtime.artifacts]] and [[runtime.deploy]] entries; [hooks] and [hooks.<event>]; a feature's table keys and [features] default; [profile] ndebug and trim_paths; [test] windows_code_page and windows_long_paths; [resources.version-info]; [pack.bundle-project]; [xlings] keys, [xlings.workspace], [xlings.overrides] and [tools.overrides]. Each new key's `since` is the first release whose reader contains it. A table reads as the longest leading run of its segments that names a section, so a sub-table with keys of its own is completed with them; `workspace.<table>` reads as the table it mirrors (a mirrored selector's build table was `target`). A table written only under a selector is offered as `[target.'cfg(...)'.<table>]` with the selector to fill in. Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- CHANGELOG.md | 11 +- spec/toml-schema.json | 691 +++++++++++++++++++++++++++++++++++++++- src/manifest.cppm | 74 +++-- tests/test_manifest.cpp | 31 +- 4 files changed, 754 insertions(+), 53 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 331ea8c..2cdb517 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,10 +13,13 @@ The first release of mcpp-ide: one backend for mcpp's editor integrations, the V - Shared panels: project, targets and platforms, libraries, dependency and module graphs, cache, pack, settings. - VS Code: tasks, Testing view, debug configurations, Problems from mcpp, mcpp.toml editing help. -- mcpp.toml and build.mcpp editing help over mcpp 2026.10.27.1's keys and directives: `[platform]` - and its tables, `[host]`, a selector's platform overrides (`platform`, `carrier`, `layers`, - `tools`, `link`, `runners`, `run_under`), `[pack]`'s `linkage`, `format`, `compress`, `sign` and - `universal`; the protocol 17 directives, completed by the typed API's names (`mcpp::link_driver`). +- mcpp.toml and build.mcpp editing help over every table and key mcpp 2026.10.27.1 reads, each with + the release that added it: `[platform]` and its tables, `[host]`, a selector's platform overrides + (`platform`, `carrier`, `layers`, `tools`, `link`, `runners`, `run_under`) and its ABI tables + (`abi`, `requires_abi`, `feature-requires-abi`), `[pack]` and `[pack.bundle-project]`, `[c-abi]`, + `[kernel-abi]`, `[runtime]` and its entry tables, `[hooks]` and each event's table, a feature's + table, `[xlings]`, `[workspace]`; the protocol 17 directives, completed by the typed API's names + (`mcpp::link_driver`). - CLion: run configurations with a PTY console, test tree, CLion's debugger, console links, the mcpp tool window; depends on the mcppls CLion plugin. - One package per editor for every system: the backend as one ok-image bundle (x86_64 and aarch64 diff --git a/spec/toml-schema.json b/spec/toml-schema.json index 9f28c86..6f4c51d 100644 --- a/spec/toml-schema.json +++ b/spec/toml-schema.json @@ -2,6 +2,28 @@ "sourceVersion": "2026.10.27.1", "sourceCommit": "e0b1133dd2912f539ee68a06724cb524e3531f46", "sections": [ + { + "header": "[target.<selector>.abi]", + "name": "abi", + "plane": "condition", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/22-target-side.md#abi--a-switch-the-whole-artefact-shares-mcpp-20269122", + "deprecatedBy": null, + "selector": true, + "keys": [ + { + "key": "exceptions", + "type": "boolean", + "since": "2026.9.12.3", + "note": "whether the artefact is built with exceptions" + }, + { + "key": "threads", + "type": "boolean", + "since": "2026.9.12.2", + "note": "whether the artefact is built with threads" + } + ] + }, { "header": "[build]", "name": "build", @@ -190,16 +212,58 @@ { "header": "[c-abi]", "name": "c-abi", - "plane": "unclassified", - "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md", - "deprecatedBy": null + "plane": "identity", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/22-target-side.md#the-c-environment-a-c-abi-package-presents-mcpp-2026918", + "deprecatedBy": null, + "keys": [ + { + "key": "builtins", + "type": "enum", + "values": [ + "iso", + "platform" + ], + "since": "2026.9.18.1", + "note": "the builtin macros the realisation defines" + }, + { + "key": "data-model", + "type": "enum", + "values": [ + "arch-default", + "lp64", + "llp64", + "ilp32" + ], + "since": "2026.9.18.1", + "note": "required" + }, + { + "key": "presents", + "type": "enum", + "values": [ + "posix", + "windows", + "none" + ], + "since": "2026.9.18.1", + "note": "the environment identity the C library presents (required)" + }, + { + "key": "wchar", + "type": "number", + "since": "2026.9.18.1", + "note": "the bits of wchar_t, 16 or 32 (required)" + } + ] }, { "header": "[c-abi-absent]", "name": "c-abi-absent", "plane": "unclassified", - "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md", - "deprecatedBy": null + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/22-target-side.md#the-c-environment-a-c-abi-package-presents-mcpp-2026918", + "deprecatedBy": null, + "openKeys": true }, { "header": "[capabilities]", @@ -229,6 +293,15 @@ "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md", "deprecatedBy": null }, + { + "header": "[target.<selector>.feature-requires-abi]", + "name": "feature-requires-abi", + "plane": "condition", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/06-features-and-capabilities.md#provides--requires--capabilities-backend-selection", + "deprecatedBy": null, + "selector": true, + "openKeys": true + }, { "header": "[feature-xlings]", "name": "feature-xlings", @@ -240,8 +313,83 @@ "header": "[features]", "name": "features", "plane": "gate", - "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#28-features--features", - "deprecatedBy": null + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/06-features-and-capabilities.md#features--features-cargo-style-additive", + "deprecatedBy": null, + "keys": [ + { + "key": "default", + "type": "array", + "since": "0.0.47", + "note": "the features a consumer gets unless it opts out" + }, + { + "key": "defines", + "type": "array", + "since": "0.0.69", + "note": "[features.<name>]: defines the active feature adds to the package's units" + }, + { + "key": "device_extensions", + "type": "array", + "since": "2026.9.7.1", + "note": "[features.<name>]: the source extensions of a device language this rule package compiles" + }, + { + "key": "flags", + "type": "array", + "since": "0.0.101", + "note": "[[features.<name>.flags]]: { glob, cflags, cxxflags, defines } tables for the feature's sources", + "unmodelled": true + }, + { + "key": "forward", + "type": "array", + "since": "0.0.99", + "note": "[features.<name>]: \"<dependency>/<feature>\" entries activated with this feature" + }, + { + "key": "implies", + "type": "array", + "since": "0.0.69", + "note": "[features.<name>]: the features this one activates" + }, + { + "key": "provides", + "type": "array", + "since": "0.0.69", + "note": "[features.<name>]: the capabilities the feature provides" + }, + { + "key": "requires", + "type": "array", + "since": "0.0.69", + "note": "[features.<name>]: the capabilities the feature requires" + }, + { + "key": "requires_abi", + "type": "table", + "since": "2026.9.12.2", + "note": "[features.<name>]: { threads, exceptions } the artefact's ABI switch must have when the feature is active" + }, + { + "key": "rule_module", + "type": "string", + "since": "2026.9.7.1", + "note": "[features.<name>]: the module of the build rule this feature contributes" + }, + { + "key": "sources", + "type": "array", + "since": "0.0.95", + "note": "[features.<name>]: sources compiled only when the feature is active" + }, + { + "key": "tools", + "type": "array", + "since": "2026.9.27.1", + "note": "[features.<name>]: the host tools the feature makes available" + } + ] }, { "header": "[generated_files]", @@ -255,7 +403,134 @@ "name": "hooks", "plane": "lifecycle", "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#216-hooks--project-build-lifecycle-commands", - "deprecatedBy": null + "deprecatedBy": null, + "keys": [ + { + "key": "build_failed", + "type": "string", + "since": "2026.8.30.2", + "note": "a command string, or a table with cmd and timeout_seconds" + }, + { + "key": "build_finished", + "type": "string", + "since": "2026.8.30.2", + "note": "a command string, or a table with cmd and timeout_seconds" + }, + { + "key": "build_start", + "type": "string", + "since": "2026.8.30.2", + "note": "a command string, or a table with cmd and timeout_seconds" + }, + { + "key": "during_build", + "type": "string", + "since": "2026.8.30.2", + "note": "a command string, or a table with cmd and loop: runs for as long as the build" + }, + { + "key": "enabled", + "type": "boolean", + "since": "2026.8.30.2" + }, + { + "key": "side_effect", + "type": "boolean", + "since": "2026.8.30.2", + "note": "true is not available yet" + }, + { + "key": "timeout_seconds", + "type": "number", + "since": "2026.8.30.2", + "note": "the default bound of a self-closing hook, at most 86400" + } + ] + }, + { + "header": "[hooks.build_failed]", + "name": "hooks.build_failed", + "plane": "lifecycle", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#216-hooks--project-build-lifecycle-commands", + "deprecatedBy": null, + "keys": [ + { + "key": "cmd", + "type": "string", + "since": "2026.8.30.2", + "note": "required" + }, + { + "key": "timeout_seconds", + "type": "number", + "since": "2026.8.30.2", + "note": "seconds, at most 86400" + } + ] + }, + { + "header": "[hooks.build_finished]", + "name": "hooks.build_finished", + "plane": "lifecycle", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#216-hooks--project-build-lifecycle-commands", + "deprecatedBy": null, + "keys": [ + { + "key": "cmd", + "type": "string", + "since": "2026.8.30.2", + "note": "required" + }, + { + "key": "timeout_seconds", + "type": "number", + "since": "2026.8.30.2", + "note": "seconds, at most 86400" + } + ] + }, + { + "header": "[hooks.build_start]", + "name": "hooks.build_start", + "plane": "lifecycle", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#216-hooks--project-build-lifecycle-commands", + "deprecatedBy": null, + "keys": [ + { + "key": "cmd", + "type": "string", + "since": "2026.8.30.2", + "note": "required" + }, + { + "key": "timeout_seconds", + "type": "number", + "since": "2026.8.30.2", + "note": "seconds, at most 86400" + } + ] + }, + { + "header": "[hooks.during_build]", + "name": "hooks.during_build", + "plane": "lifecycle", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#216-hooks--project-build-lifecycle-commands", + "deprecatedBy": null, + "keys": [ + { + "key": "cmd", + "type": "string", + "since": "2026.8.30.2", + "note": "required" + }, + { + "key": "loop", + "type": "boolean", + "since": "2026.8.30.2", + "note": "whether the command is restarted when it exits" + } + ] }, { "header": "[host]", @@ -283,8 +558,22 @@ "header": "[kernel-abi]", "name": "kernel-abi", "plane": "unclassified", - "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md", - "deprecatedBy": null + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/22-target-side.md#the-c-environment-a-c-abi-package-presents-mcpp-2026918", + "deprecatedBy": null, + "keys": [ + { + "key": "provides-interfaces", + "type": "array", + "since": "2026.9.20.1", + "note": "the interfaces of the layer this package provides (only its provider)" + }, + { + "key": "requires-interfaces", + "type": "array", + "since": "2026.9.20.1", + "note": "the interfaces of the layer this package requires" + } + ] }, { "header": "[language]", @@ -434,6 +723,27 @@ } ] }, + { + "header": "[pack.bundle-project]", + "name": "pack.bundle-project", + "plane": "unclassified", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/10-pack-and-release.md#configuration", + "deprecatedBy": null, + "keys": [ + { + "key": "also_skip", + "type": "array", + "since": "0.0.1", + "note": "libraries assumed to exist on the target system" + }, + { + "key": "force_bundle", + "type": "array", + "since": "0.0.1", + "note": "libraries bundled even when the PEP 600 list names them" + } + ] + }, { "header": "[package]", "name": "package", @@ -513,7 +823,9 @@ }, { "key": "requires_abi", - "type": "array" + "type": "table", + "since": "2026.9.12.2", + "note": "{ threads, exceptions }: the artefact's ABI switches this package requires" }, { "key": "standard", @@ -914,6 +1226,12 @@ "type": "boolean", "note": "-flto" }, + { + "key": "ndebug", + "type": "boolean", + "since": "2026.10.24.1", + "note": "whether NDEBUG is defined for the profile's units" + }, { "key": "opt", "type": "enum", @@ -928,6 +1246,34 @@ "key": "strip", "type": "boolean", "note": "-s at link time" + }, + { + "key": "trim_paths", + "type": "boolean", + "since": "2026.10.24.1", + "note": "whether the build's own paths are rewritten out of the artifacts" + } + ] + }, + { + "header": "[target.<selector>.requires_abi]", + "name": "requires_abi", + "plane": "condition", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/06-features-and-capabilities.md#provides--requires--capabilities-backend-selection", + "deprecatedBy": null, + "selector": true, + "keys": [ + { + "key": "exceptions", + "type": "boolean", + "since": "2026.9.12.3", + "note": "the artefact's exceptions switch this package requires" + }, + { + "key": "threads", + "type": "boolean", + "since": "2026.9.12.2", + "note": "the artefact's threads switch this package requires" } ] }, @@ -956,19 +1302,253 @@ } ] }, + { + "header": "[resources.version-info]", + "name": "resources.version-info", + "plane": "metadata", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#215-resources--metadata-and-assets-embedded-in-the-artifact-2026871", + "deprecatedBy": null, + "keys": [ + { + "key": "company", + "type": "string", + "since": "2026.8.7.1" + }, + { + "key": "copyright", + "type": "string", + "since": "2026.8.7.1" + }, + { + "key": "description", + "type": "string", + "since": "2026.8.7.1" + }, + { + "key": "internal-name", + "type": "string", + "since": "2026.8.7.1" + }, + { + "key": "original-filename", + "type": "string", + "since": "2026.8.7.1" + }, + { + "key": "product", + "type": "string", + "since": "2026.8.7.1" + } + ] + }, { "header": "[runtime]", "name": "runtime", "plane": "metadata", "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#211-runtime--provider-neutral-runtime-contract", - "deprecatedBy": null + "deprecatedBy": null, + "keys": [ + { + "key": "artifacts", + "type": "array", + "since": "2026.8.10.1", + "note": "[[runtime.artifacts]]: prebuilt artifacts the package provides", + "unmodelled": true + }, + { + "key": "capabilities", + "type": "array", + "since": "0.0.46" + }, + { + "key": "deploy", + "type": "array", + "since": "2026.9.12.2", + "note": "[[runtime.deploy]]: { from, to } files placed beside the artifact", + "unmodelled": true + }, + { + "key": "deploy_files", + "type": "array", + "since": "2026.8.10.1", + "note": "files placed beside the artifact" + }, + { + "key": "dlopen_libs", + "type": "array", + "since": "0.0.46", + "note": "libraries the program opens at run time" + }, + { + "key": "frameworks", + "type": "array", + "since": "2026.8.10.1" + }, + { + "key": "libraries", + "type": "array", + "since": "2026.8.10.1" + }, + { + "key": "library_dirs", + "type": "array", + "since": "0.0.46" + }, + { + "key": "link_library_dirs", + "type": "array", + "since": "2026.8.10.1" + }, + { + "key": "provides", + "type": "array", + "since": "0.0.48" + }, + { + "key": "requirements", + "type": "array", + "since": "2026.8.10.1", + "note": "[[runtime.requirements]]: { kind, value, phase, required, discovery }", + "unmodelled": true + }, + { + "key": "runtime_search_dirs", + "type": "array", + "since": "2026.8.10.1" + }, + { + "key": "transitive_needed_dirs", + "type": "array", + "since": "2026.8.10.1" + } + ] + }, + { + "header": "[[runtime.artifacts]]", + "name": "runtime.artifacts", + "plane": "metadata", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#211-runtime--provider-neutral-runtime-contract", + "deprecatedBy": null, + "keys": [ + { + "key": "abi", + "type": "string", + "since": "2026.8.10.1" + }, + { + "key": "accel", + "type": "string", + "since": "2026.9.5.1" + }, + { + "key": "digest", + "type": "string", + "since": "2026.8.10.1" + }, + { + "key": "host_fingerprint", + "type": "string", + "since": "2026.8.10.1" + }, + { + "key": "path", + "type": "string", + "since": "2026.8.10.1" + }, + { + "key": "provenance", + "type": "string", + "since": "2026.8.10.1" + }, + { + "key": "role", + "type": "string", + "since": "2026.8.10.1" + } + ] + }, + { + "header": "[[runtime.deploy]]", + "name": "runtime.deploy", + "plane": "metadata", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#211-runtime--provider-neutral-runtime-contract", + "deprecatedBy": null, + "keys": [ + { + "key": "from", + "type": "string", + "since": "2026.9.12.2", + "note": "a file of the package or of the build" + }, + { + "key": "to", + "type": "string", + "since": "2026.9.12.2", + "note": "its path relative to the artifact's directory" + } + ] + }, + { + "header": "[[runtime.requirements]]", + "name": "runtime.requirements", + "plane": "metadata", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#211-runtime--provider-neutral-runtime-contract", + "deprecatedBy": null, + "keys": [ + { + "key": "discovery", + "type": "string", + "since": "2026.8.10.3" + }, + { + "key": "kind", + "type": "string", + "since": "2026.8.10.1", + "note": "required" + }, + { + "key": "phase", + "type": "enum", + "values": [ + "link", + "run" + ], + "since": "2026.8.10.1", + "note": "required" + }, + { + "key": "required", + "type": "boolean", + "since": "2026.8.10.1" + }, + { + "key": "value", + "type": "string", + "since": "2026.8.10.1", + "note": "required" + } + ] }, { "header": "[scan_overrides]", "name": "scan_overrides", "plane": "unclassified", "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#283-scan_overridesglob--author-asserted-scan-results", - "deprecatedBy": null + "deprecatedBy": null, + "keys": [ + { + "key": "imports", + "type": "array", + "since": "0.0.85", + "note": "the modules the unit imports" + }, + { + "key": "provides", + "type": "array", + "since": "0.0.85", + "note": "the module the unit provides, at most one" + } + ] }, { "header": "[target]", @@ -1174,6 +1754,22 @@ "type": "string", "since": "2026.10.26.2", "note": "the symbol every test image is entered at, on a freestanding target" + }, + { + "key": "windows_code_page", + "type": "enum", + "values": [ + "utf-8", + "legacy" + ], + "since": "2026.10.5.2", + "note": "the code page of every test program on Windows" + }, + { + "key": "windows_long_paths", + "type": "boolean", + "since": "2026.10.16.1", + "note": "whether every test program on Windows opts into long paths" } ] }, @@ -1216,19 +1812,84 @@ "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md", "deprecatedBy": null }, + { + "header": "[tools.overrides]", + "name": "tools.overrides", + "plane": "tool", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/30-build-mcpp.md#toolsoverrides--use-an-existing-binary", + "deprecatedBy": null, + "openKeys": true + }, { "header": "[workspace]", "name": "workspace", "plane": "unclassified", "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#218-workspace--tables-a-workspace-shares-202610101", - "deprecatedBy": null + "deprecatedBy": null, + "keys": [ + { + "key": "exclude", + "type": "array", + "since": "0.0.11", + "note": "member globs left out" + }, + { + "key": "members", + "type": "array", + "since": "0.0.11", + "note": "member directories or globs" + } + ] }, { "header": "[xlings]", "name": "xlings", "plane": "tool", "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#213-xlings--the-projects-environment", - "deprecatedBy": null + "deprecatedBy": null, + "keys": [ + { + "key": "deps", + "type": "array", + "since": "0.0.77", + "note": "the project's host build tools: \"<name>@<version>\" or tables", + "unmodelled": true + }, + { + "key": "overrides", + "type": "table", + "since": "2026.10.1.3", + "note": "<package> = <version or source>: what a dependency's xlings entries resolve to; usually [xlings.overrides]" + }, + { + "key": "subos", + "type": "string", + "since": "0.0.77", + "note": "the SubOS the project's environment is materialised in" + }, + { + "key": "workspace", + "type": "table", + "since": "0.0.77", + "note": "<tool> = \"<version>\": the project's tool pins; usually [xlings.workspace]" + } + ] + }, + { + "header": "[xlings.overrides]", + "name": "xlings.overrides", + "plane": "tool", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#213-xlings--the-projects-environment", + "deprecatedBy": null, + "openKeys": true + }, + { + "header": "[xlings.workspace]", + "name": "xlings.workspace", + "plane": "tool", + "doc": "https://github.com/mcpp-community/mcpp/blob/main/docs/04-mcpp-toml.md#213-xlings--the-projects-environment", + "deprecatedBy": null, + "openKeys": true } ], "rules": [ diff --git a/src/manifest.cppm b/src/manifest.cppm index 55f2793..f1851f8 100644 --- a/src/manifest.cppm +++ b/src/manifest.cppm @@ -148,42 +148,40 @@ std::string key_doc(const Json& section, const Json& key) { return doc; } -// The section of a platform's table, from the segments after `platform` or -// after a selector (SPEC-013 §1, §2): `layers` is `platform.layers`, a -// `cfg(...)` table of `build` is `platform.build`, the entries of -// `link.inputs` are `platform.link.inputs`, the layers a host triple takes are -// `platform.layers`. Empty for a table that is not one of a platform's. -std::string platform_table(std::span<const std::string> rest) { - static constexpr std::string_view kTables[] = {"build", "carrier", "hosted", "layers", - "link", "runners", "tools", "versions"}; - if (rest.empty() || std::ranges::find(kTables, rest[0]) == std::end(kTables)) return {}; - if (rest.size() >= 2 && rest[0] == "link" && rest[1] == "inputs") return "platform.link.inputs"; - if (rest.size() >= 2 && rest[0] == "hosted" && rest[1] == "layers") return "platform.layers"; - return "platform." + rest[0]; -} - -} // namespace - -std::string section_of(std::string_view table) { - auto seg = segments(table); +// The section the segments of a table name read as. The longest leading run +// that names a section of the schema is that section (`pack.bundle-project`, +// `runtime.requirements`, `platform.link.inputs`, `hooks.during_build`), else +// the first segment (`profile.release` is `profile`, `targets.app` is +// `targets`). Three tables read otherwise: +// - `workspace.<table>` is `<table>`, the table it mirrors; +// - `target.<selector>.<table>` is `<table>`, and a platform's table there +// (carrier, layers, link, runners, tools) is the platform's; +// - a `requires_abi` table, of `[package]` or of a feature, is `requires_abi`. +// The layers a host triple takes (`platform.hosted.layers`) are `platform.layers`. +std::string section_of_segments(std::span<const std::string> seg) { if (seg.empty()) return {}; - // A `target.<selector>` table reads as the table after the selector, and a - // platform's table there as the platform's. + if (seg[0] == "workspace" && seg.size() >= 2) return section_of_segments(seg.subspan(1)); if (seg[0] == "target" && seg.size() >= 3) { - // The tables a selector overrides a platform with (`build` there is - // the project's `[build]`; `hosted` and `versions` are a platform's own). static constexpr std::string_view kOverrides[] = {"carrier", "layers", "link", "runners", "tools"}; - if (std::ranges::find(kOverrides, seg[2]) != std::end(kOverrides)) - return platform_table(std::span(seg).subspan(2)); - return seg[2]; + if (std::ranges::find(kOverrides, seg[2]) == std::end(kOverrides)) return section_of_segments(seg.subspan(2)); + std::vector<std::string> platform{"platform"}; + platform.insert(platform.end(), seg.begin() + 2, seg.end()); + return section_of_segments(platform); } - if (seg[0] == "target") return "target"; - if (seg[0] == "platform") { - auto p = platform_table(std::span(seg).subspan(1)); - return p.empty() ? std::string("platform") : p; + if (seg.size() >= 2 && seg.back() == "requires_abi") return "requires_abi"; + if (seg.size() >= 3 && seg[0] == "platform" && seg[1] == "hosted" && seg[2] == "layers") return "platform.layers"; + std::string name, longest; + for (const auto& s : seg) { + name += name.empty() ? s : "." + s; + if (section_named(name)) longest = name; } - if (seg[0] == "workspace" && seg.size() >= 2) return seg[1] == "package" ? "package" : seg[1]; - return seg[0]; + return longest.empty() ? seg[0] : longest; +} + +} // namespace + +std::string section_of(std::string_view table) { + return section_of_segments(segments(table)); } Context context_at(std::string_view text, int line, int character) { @@ -255,9 +253,19 @@ Json complete(const Json& p) { for (const auto& s : schema()["sections"]) { if (!s.value("deprecatedBy", Json(nullptr)).is_null()) continue; const auto header = s.value("header", ""); + const auto doc = s.contains("doc") && s["doc"].is_string() ? s["doc"] : Json(""); + // A table written only under a selector (`[target.<selector>.abi]`) is + // offered with the selector to fill in. + if (s.value("selector", false)) { + const auto tail = header.substr(header.find("<selector>") + std::string_view("<selector>").size()); + items.push_back(Json{{"label", "[target.'cfg(...)'" + tail}, {"kind", "template"}, + {"detail", s.value("plane", "")}, {"documentation", doc}, + {"insertText", "[target.'cfg(${1:os = \"linux\"})'" + tail}, + {"snippet", true}, {"range", range}}); + continue; + } items.push_back(Json{{"label", header}, {"kind", "section"}, {"detail", s.value("plane", "")}, - {"insertText", header}, {"range", range}, - {"documentation", s.contains("doc") && s["doc"].is_string() ? s["doc"] : Json("")}}); + {"insertText", header}, {"range", range}, {"documentation", doc}}); } // The forms that name something: a dependency namespace, a target, a selector. for (auto [label, snippet, detail] : std::initializer_list<std::tuple<const char*, const char*, const char*>>{ diff --git a/tests/test_manifest.cpp b/tests/test_manifest.cpp index acb51da..21f6a4d 100644 --- a/tests/test_manifest.cpp +++ b/tests/test_manifest.cpp @@ -27,7 +27,21 @@ int main() { CHECK(manifest::section_of("target.'cfg(platform = \"openkal\")'.layers") == "platform.layers"); CHECK(manifest::section_of("target.x86_64-openkal.link") == "platform.link"); CHECK(manifest::section_of("target.x86_64-openkal.versions") == "versions"); - CHECK(manifest::section_of("tools.overrides") == "tools"); + CHECK(manifest::section_of("tools.overrides") == "tools.overrides"); + // A sub-table that is a section of its own, a mirrored table, the ABI switches. + CHECK(manifest::section_of("pack.bundle-project") == "pack.bundle-project"); + CHECK(manifest::section_of("runtime.requirements") == "runtime.requirements"); + CHECK(manifest::section_of("hooks.during_build") == "hooks.during_build"); + CHECK(manifest::section_of("resources.version-info") == "resources.version-info"); + CHECK(manifest::section_of("xlings.workspace") == "xlings.workspace"); + CHECK(manifest::section_of("profile.release") == "profile"); + CHECK(manifest::section_of("features.gpu") == "features"); + CHECK(manifest::section_of("workspace.package") == "package"); + CHECK(manifest::section_of("workspace.target.'cfg(os = \"linux\")'.build") == "build"); + CHECK(manifest::section_of("target.'cfg(os = \"linux\")'.abi") == "abi"); + CHECK(manifest::section_of("target.x86_64-linux-gnu.feature-requires-abi") == "feature-requires-abi"); + CHECK(manifest::section_of("package.requires_abi") == "requires_abi"); + CHECK(manifest::section_of("features.mt.requires_abi") == "requires_abi"); const std::string text = "[package]\nname = \"a\"\n\n[build]\nbmi_schedule = \"\"\n\n"; auto keys = labels(manifest::complete(Json{{"text", text}, {"line", 5}, {"character", 0}})); @@ -64,5 +78,20 @@ int main() { CHECK(has(pack, "format") && has(pack, "compress") && has(pack, "universal") && has(pack, "sign")); auto ph = labels(manifest::complete(Json{{"text", "[plat"}, {"line", 0}, {"character", 5}})); CHECK(has(ph, "[platform]") && has(ph, "[platform.link]") && has(ph, "[[platform.link.inputs]]") && has(ph, "[host]")); + // Every table mcpp 2026.10.27.1 reads has its keys. + const std::string more = "[c-abi]\n\n[profile.release]\n\n[hooks.during_build]\n\n[target.'cfg(os = \"linux\")'.abi]\n\n" + "[[runtime.requirements]]\n\n[features.mt]\n\n[xlings]\n\n[test]\n"; + auto keysAt = [&](int line) { return labels(manifest::complete(Json{{"text", more}, {"line", line}, {"character", 0}})); }; + auto cabi = keysAt(1); + CHECK(has(cabi, "presents") && has(cabi, "data-model") && has(cabi, "wchar") && has(cabi, "builtins")); + CHECK(has(keysAt(3), "ndebug") && has(keysAt(3), "trim_paths")); + CHECK(has(keysAt(5), "loop") && !has(keysAt(5), "timeout_seconds")); + CHECK(has(keysAt(7), "threads") && has(keysAt(7), "exceptions")); + CHECK(has(keysAt(9), "phase") && has(keysAt(9), "discovery")); + CHECK(has(keysAt(11), "implies") && has(keysAt(11), "requires_abi") && has(keysAt(11), "rule_module")); + CHECK(has(keysAt(13), "subos") && has(keysAt(13), "deps")); + CHECK(has(keysAt(15), "windows_code_page") && has(keysAt(15), "windows_long_paths")); + auto th = labels(manifest::complete(Json{{"text", "[tar"}, {"line", 0}, {"character", 4}})); + CHECK(has(th, "[target.'cfg(...)'.abi]") && has(th, "[target.'cfg(...)'.requires_abi]") && !has(th, "[target.<selector>.abi]")); std::println("test_manifest: ok"); } From 858362b17f8cb63460f2c852e00d486b57e0d196 Mon Sep 17 00:00:00 2001 From: Sunrisepeak <speakshen@163.com> Date: Thu, 29 Oct 2026 00:46:38 +0900 Subject: [PATCH 30/30] mcpplibs.os 0.2.1 as an index version; mcpp.lock as mcpp 2026.10.27.1 writes it, each entry with the configurations that resolved it Co-authored-by: speak-agent <248744407+speak-agent@users.noreply.github.com> --- CHANGELOG.md | 2 ++ mcpp.lock | 20 +++++++++++++++----- mcpp.toml | 9 ++++----- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2cdb517..d1184b6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -26,3 +26,5 @@ The first release of mcpp-ide: one backend for mcpp's editor integrations, the V images on openkal-platform 0.17.3) with okrun for Linux x86_64/aarch64, macOS arm64 and Windows x64; CI starts it from both packages on each of those systems. - `mcpp pack`'s package format is passed as `--pkg-format` where mcpp offers it (`--format` before). +- The operating system through mcpplibs.os 0.2.1 (an index version), whose ok-image targets take + their C library, C++ run-time and loader from openkal-platform. diff --git a/mcpp.lock b/mcpp.lock index 35291b8..2c6d32f 100644 --- a/mcpp.lock +++ b/mcpp.lock @@ -5,23 +5,20 @@ # file must not change depending on which command ran last. version = 2 -[package."os"] -version = "os-0.2.1" -source = "git+https://github.com/mcpplibs/os.git#branch=os-0.2.1@211e765edbed99ef02526c45af9da988f6e48399" -hash = "fnv1a:e9ea51f425a4832f" - [package."mcpp.plugins"] namespace = "mcpp" version = "0.20.0" source = "index+mcpp@0.20.0" hash = "fnv1a:9438fb3cbe77fdc7" origin = "platform" +targets = ["aarch64-openkal", "x86_64-openkal"] [package."openkal"] namespace = "mcpplibs" version = "0.17.1" source = "index+mcpplibs@0.17.1" hash = "fnv1a:d9a6fd1043f0f322" +targets = ["aarch64-openkal", "x86_64-linux-gnu", "x86_64-openkal"] [package."openkal-ld"] namespace = "mcpplibs" @@ -29,6 +26,7 @@ version = "0.1.3" source = "index+mcpplibs@0.1.3" hash = "fnv1a:c45ba7726c74fc44" origin = "platform" +targets = ["aarch64-openkal", "x86_64-openkal"] [package."openkal-linux"] namespace = "mcpplibs" @@ -42,6 +40,7 @@ version = "0.16.6" source = "index+mcpplibs@0.16.6" hash = "fnv1a:1310f13360b2df3f" origin = "platform" +targets = ["aarch64-openkal", "x86_64-openkal"] [package."openkal-musl"] namespace = "mcpplibs" @@ -49,6 +48,7 @@ version = "0.22.6" source = "index+mcpplibs@0.22.6" hash = "fnv1a:de2d14df84a5a777" origin = "platform" +targets = ["aarch64-openkal", "x86_64-openkal"] [package."openkal-platform"] namespace = "mcpplibs" @@ -56,6 +56,7 @@ version = "0.17.3" source = "index+mcpplibs@0.17.3" hash = "fnv1a:d470e612205b7986" origin = "platform" +targets = ["aarch64-openkal", "x86_64-openkal"] [package."openkal-tools"] namespace = "mcpplibs" @@ -63,10 +64,19 @@ version = "0.1.3" source = "index+mcpplibs@0.1.3" hash = "fnv1a:3a0aa473e0da7eaf" origin = "platform" +targets = ["aarch64-openkal", "x86_64-openkal"] + +[package."mcpplibs.os"] +namespace = "mcpplibs" +version = "0.2.1" +source = "index+mcpplibs@0.2.1" +hash = "fnv1a:d0be97a50033077e" +targets = ["aarch64-openkal", "x86_64-linux-gnu", "x86_64-openkal"] [package."nlohmann.json"] namespace = "nlohmann" version = "3.12.0" source = "index+nlohmann@3.12.0" hash = "fnv1a:65af05f998b1b9d7" +targets = ["aarch64-openkal", "x86_64-linux-gnu", "x86_64-openkal"] diff --git a/mcpp.toml b/mcpp.toml index 446e3cb..d588935 100644 --- a/mcpp.toml +++ b/mcpp.toml @@ -62,11 +62,10 @@ main = "src/bin/mockmcpp.cpp" kind = "bin" main = "src/bin/dev.cpp" -[dependencies] -# os 0.2.1 (mcpplibs/os#7): an ok image's C library, C++ run-time and loader are its platform's, -# so the package declares no openkal-tools of its own beside the platform's. By its branch until -# it is published. -os = { git = "https://github.com/mcpplibs/os.git", branch = "os-0.2.1" } +[dependencies.mcpplibs] +# os 0.2.1: an ok image's C library, C++ run-time and loader are its platform's, so the package +# declares no openkal-tools of its own beside the platform's. +os = "0.2.1" [dependencies.nlohmann] json = "3.12.0"