bunnia

    MoonBit mini-app UI framework with Rabbita-style authoring and modular platform adapters.

    miniapp
    wechat
    alipay
    tiktok
    ui
    Download zip
    Author
    Version
    0.1.0
    License
    Apache-2.0
    Last updated
    3 months ago
    Downloads
    33

    No dependencies

    #vectie/bunnia

    Bunnia is a MoonBit mini-app UI framework experiment with Rabbita-style authoring and modular platform adapters.

    The main goal is fast, high-quality rendering for large mini-apps. Translation from Rabbita/Moontown should be easier, but rendering speed, visual quality, and predictable generated output size are the priorities.

    Bunnia is also intended for agentic mini-apps. Agent chat, action traces, streaming status, and reviewable tool results should be first-class UI patterns, not bolted-on product widgets.

    Agent interaction and communication should also be first-class: agent-to-human, agent-to-agent, handoff, review, and broadcast patterns should have reusable framework support inspired by Moontown, without importing Moontown concepts into core APIs.

    Bunnia should also support stylised map-style surfaces for large stateful apps: scene layers, positioned actors, status overlays, and asset-budgeted rendering should be framework patterns rather than one-off product code.

    Bunnia should keep a few MoonSuite lessons in mind without becoming a heavy suite platform: stable ids, small deltas, visible loading/error status, reviewable risky actions, artifact links, and generated-output diagnostics.

    The first target is WeChat Mini Program, but the core tree model is platform neutral so Alipay and TikTok adapters can be added without rewriting product views.

    Bunnia is a dedicated framework. Moontown/Wenyu can be used as a reference app and stress test, but Moontown product concepts must not be mixed into Bunnia's core framework APIs.

    See docs/ROADMAP.md for the phase-by-phase implementation plan.

    See docs/MOONTOWN_MINIAPP_PLAN.md for the Moontown product/backend dogfood plan, including user login, building ownership, publication, search, books, and agent interaction.

    See docs/MOONTOWN_REALM_MIGRATION_PLAN.md for the focused migration plan where Realm is the existing tile map and the remaining work is the mature mini-app functionality around it.

    #Package Shape

    • core: platform-neutral tree, events, adapters, render planning, and generic surface-status badges/overlays for loading, stale, error, retry, cancelled, and degraded states.
    • program: pure Program[Model, Msg] update/view boundary with pending effects and patch plans.
    • agent: lightweight message, review, artifact-link, run-status, and communication planning primitives, plus generic communication threads and traces.
    • scene: static stylised map model with layers, selectable regions, markers, asset manifests, hit targets, thread-link plans, and bounded updates.
    • effects: typed frontend effect descriptions, platform support planning, snapshot-delta planning, cancel/retry helpers, and backend contract paths.
    • adapters/wechat: WeChat Mini Program output generation.
    • tooling: build-profile diagnostics that aggregate render, WeChat, patch, backend, snapshot-delta, agent-delta, asset, and scene budget signals.
    • examples/agent_map: small downstream example combining agentic UI, review controls, patches, and a static map surface.
    • examples/wenyu_overview: product-shaped proof slice that keeps Wenyu projection/view code outside the framework core.
    • examples/moontown_miniapp: product-shaped Moontown mini-app vertical slice with full-screen map, building search/place flows, agent chat, mock local backend contracts, and create-building/create-agent controls outside core.
    • root package: small @bunnia facade for app authors.

    #Generate The Demo

    Print the CLI command map without writing generated output:

    moon run cmd/main -- help

    Unknown positional commands fail before the generator writes files, so command typos do not accidentally produce stale output.

    moon run cmd/main

    This writes a WeChat Mini Program file set to _build/bunnia/wechat/agent_map. The default demo includes initial page data plus event-to-patch dispatch for review buttons, map regions, and map markers. The command also prints render, file-size, initial-data, event-patch byte/operation, patch, agent-delta, and build-profile budget summaries. Use --out to choose another directory:

    moon run cmd/main -- --out /tmp/bunnia-agent-map

    The Moontown mini-app slice uses the same build path:

    moon run cmd/main -- build --target wechat --example moontown_miniapp --strict --budget large --render-budget large moon run cmd/main -- inspect --target wechat --example moontown_miniapp --budget large --render-budget large sh scripts/validate_moontown_ordinary_copy.sh

    For WeChat DevTools backend calls, start the local Moontown example backend on this Mac:

    node examples/moontown_miniapp/backend/local_backend.mjs --reset-state node examples/moontown_miniapp/backend/local_backend.mjs --smoke

    The same generator also accepts explicit build-style arguments:

    moon run cmd/main -- build --target wechat --strict

    --strict fails the command when render, generated-file, patch, effect, build-profile, or inspection-gate diagnostics are present. Use --budget tight for a stricter generated-output gate, or --budget tiny when testing that CI fails on size and route-pressure regressions:

    moon run cmd/main -- build --target wechat --strict --budget tight

    The render planner uses the same named profile by default. Use --render-budget tiny to exercise render-budget failures without shrinking generated-output byte budgets. Named budget profiles are exposed through @bunnia.render_budget_for_profile(...) and @bunnia.wechat_build_budget_for_profile(...); route-risk and update-payload gates are exposed through @bunnia.inspection_budget_for_profile(...), and aggregate large-app profile gates are exposed through @bunnia.build_profile_budget_for_profile(...), including generated-route diagnostic, repeated-list identity, unresolved-review, tool-result acknowledgment, and scene asset deployability limits, so contributors can use the same gates outside the CLI.

    For local iteration, watch generated output with:

    moon run cmd/main -- watch --target wechat --example agent_map --strict

    Use --once with watch to run the same generation path once in CI or smoke tests without starting a long-running file watcher.

    For deterministic generator review in CI, write a compact generated-output snapshot without writing the full generated mini-program directory:

    moon run cmd/main -- snapshot --target wechat --example agent_map --strict

    Snapshot output records the selected --budget profile, so CI diffs include the same generated-output report and diagnostic lines that strict builds evaluate. If --render-budget is set separately, snapshots record that profile too. Snapshots also include route-scoped manifest diagnostics, so a CI diff can point directly at the generated page that owns a render, payload, or interaction issue. The same snapshot records route diagnostic counts, making route pressure visible even before reading the diagnostic lines. Snapshots also record the profile-gate and inspection-gate summaries and diagnostics, highest-risk route, and per-route inspection lines, so CI diffs can show which page should be optimized first and which strict route/profile-pressure gate fired.

    The snapshot records route, budget profile, size budgets, profile summary, profile-gate summary, per-route risk, route-scoped scene asset references, estimated scene asset bytes, and per-file byte/checksum lines without committing the full generated mini-program.

    To inspect route and file pressure without writing generated files:

    moon run cmd/main -- inspect --target wechat --example agent_map --budget tight --render-budget tight

    inspect prints the same render, manifest, report, patch, profile, and snapshot summaries as the build path, then adds a project inspection summary, the highest-risk route, max scene marker/asset/package pressure, one route-inspection line per generated page, one route=... manifest line per generated page, route-scoped scene_asset=... lines, and one file=... line per generated artifact. This is intended for quick checks of first-screen bytes, update payloads, update operation fanout, scene marker and asset pressure, packaged scene bytes, diagnostic counts, file kinds, file bytes, and checksums before opening WeChat DevTools.

    To inspect component mapping and platform capability limits:

    moon run cmd/main -- limits --target wechat

    limits prints the active platform adapter's component mappings, tap-event mapping, lifecycle names, request API, canvas/cloud/stream capabilities, and explicit generator status. The status is available for WeChat plus the generic Alipay/TikTok generators, and unknown for unsupported target ids. The same target-support model is reused by ci-plan and build-style commands, so unknown targets fail before artifacts are generated. Alipay and TikTok can write generic mini-app projects through build, including a deterministic bunnia.manifest.json route/file inventory plus named budget gates for cross-platform diagnostics. They also support no-write inspect, deterministic snapshot, and local watch regeneration paths. Generic build, inspect, snapshot, and watch flows print a target-neutral release-readiness report, and strict mode treats its diagnostics as blocking.

    To print the canonical local/CI workflow for the tight proof examples:

    moon run cmd/main -- ci-plan moon run cmd/main -- ci-plan --script sh scripts/scaffold_smoke.sh sh scripts/ci.sh

    For the product-shaped Moontown route, use the explicit large-app lane:

    moon run cmd/main -- ci-plan --example moontown_miniapp --budget large --render-budget large

    The repository GitHub Actions workflow in .github/workflows/ci.yml generates the same CI plan through scripts/ci.sh, so local and hosted CI use the same command list. To run that same gate before each commit, configure the included hook once with git config core.hooksPath .githooks.

    ci-plan defaults to the tight generated-output and render budgets and lists the check, test, interface, format, framework-boundary, platform-limits, route inspection, strict build, one-shot watch generation, snapshot, and scaffold-smoke commands that contributors should run before review. The public @bunnia.ci_plan() default stays product-neutral; the root CLI explicitly includes the Wenyu proof slice as an example stress test. Pass --render-budget to make render pressure stricter or looser than generated file-size gates. Unknown budget profile names and unsupported targets are printed as CI-plan diagnostics before contributors copy the generated commands. Use --target alipay or --target tiktok to print the same inspect, strict build, watch-once, and snapshot workflow for the generic mini-app adapters. The CI plan also prints the inspection-gate and profile-gate thresholds derived from the selected budget profile, including route-risk, update-operation ceilings, backend pressure, scene-asset ceilings, packaged scene-byte ceilings, duplicate stream chunks, full snapshot replacements, scene thread orphans, clamped cameras, surface fallbacks, visual-quality issues, and degraded scenes. That makes strict map-heavy and agent-heavy checks reviewable before the commands run. Build, inspect, and snapshot output also include a release-readiness line that aggregates manifest coverage, frontend secret checks, backend audit hooks, remote scene-asset policy, and the profile/inspection gates into a pilot preflight status. Add --script to emit a deterministic sh script from the same plan; invalid plans print diagnostics and exit before running generated commands.

    The WeChat generator also supports multi-page projects through @bunnia.wechat_project_page(...) and @bunnia.generate_wechat_project_from_pages(...). Build reports include page count, generated file sizes, initial data bytes, event patch bytes, event patch operation count, and route-level first-screen/update payload and update operation budgets so large apps can catch growth early.

    Generated WeChat projects include bunnia.manifest.json, a deterministic route and file manifest with per-page node/event counts, runtime data bytes, patch bytes, update operation counts, generated file sizes, first-screen/update byte estimates, and route-scoped render diagnostics. Generic Alipay/TikTok projects also include bunnia.manifest.json with platform id, route/file inventory, page node/event counts, scene counts, diagnostics, and generated byte totals. Generated manifests also include route-scoped scene asset references, estimated packaged scene bytes, remote scene asset counts, and an app-level sceneAssets list derived from neutral data-asset-* attributes, so map-heavy pages can review packaged and remote asset usage without importing scene-specific code in the WeChat adapter. Generated projects also include shared bunnia.runtime.js and app.wxss files plus route-local *.data.js payload modules, so page files keep only route structure and runtime glue instead of duplicating helpers, default styles, initial data, and event-patch tables per route. Generated event-patch tables include only messages reachable from that route's rendered events; orphan handlers stay visible as diagnostics instead of being serialized into page payloads. The manifest records missing and orphan event-patch counts per route, so large apps can locate broken interaction wiring without scanning aggregate logs. Route manifests also include a diagnostics array for render, payload, and interaction issues attributable to that page, plus per-route and app-level diagnostic counts/status fields so large apps can rank problematic routes without parsing every diagnostic string. @bunnia.inspect_wechat_project(...) and the inspect command use those signals to identify the top route by diagnostic and payload/render pressure. Backend-aware manifests also record reachable backend, stream, and review endpoint counts per route, making agentic request pressure attributable before opening the mini-app IDE. Projects generated with a backend contract also include bunnia.backend.js, a contract-derived wx.request adapter that keeps base URLs in page data and does not generate app secrets. Backend-aware pages call that adapter when a handled event message matches a backend endpoint id, and each page only carries the endpoint ids reachable from its own rendered events. Pages with no matching endpoint events keep the normal lightweight page runtime even inside a backend-aware project.

    For large repeated surfaces, use @bunnia.windowed_list(...) with the visible rows and the full total_count. Render plans and generated manifests report windowed_lists plus visible/total item counts, which keeps first output bounded while preserving scale diagnostics. Render plans also report unwindowed_list_children and can diagnose unwindowed-list-children-over-budget when a keyed list, feed, or trace grows too large without windowing.

    For large agentic traces, use @bunnia.plan_communications(...) or @bunnia.plan_filtered_communications(...) before rendering. Communication plans report visible/total rows, unresolved review pressure, artifact-bearing rows, and budget diagnostics; build profiles aggregate those signals in the normal CLI summary. Build profiles also carry route diagnostic route/count fields from the generated manifest so large apps can rank problematic routes from tooling output.

    For long agent conversations, use @bunnia.windowed_message_feed(...) and @bunnia.windowed_communication_trace(...) so chat rows and action traces keep the same visible/total diagnostics as other large surfaces. For tool outputs, use @bunnia.tool_result_card(...) with @bunnia.tool_result_card_view(...) or @bunnia.windowed_tool_result_card_list(...) so artifact references, run-status, open actions, and acknowledgments remain typed UI state. Use @bunnia.plan_tool_result_cards(...) before profiling large agentic surfaces so visible result cards, pending acknowledgments, missing acknowledgments, and artifact references show up in build-profile diagnostics. For streaming output, append completed chunks with @bunnia.append_stream_chunk_delta(...) and update the current in-flight chunk with @bunnia.set_stream_chunk_delta(...); agent delta plans flag duplicate appended stream chunks.

    Render plans also report unkeyed_list_children and duplicate_list_keys. Keep repeated rows uniquely keyed so large lists, feeds, and traces can update predictably. Render plans also count canvas nodes and can be planned against a custom PlatformAdapter, so unsupported canvas capability is visible before choosing a generator. Effect plans can also be checked against a custom PlatformAdapter, so streaming agent operations fail as explicit diagnostics when a target runtime cannot support them. Generic mini-app pages can be lowered for Alipay and TikTok from the same platform-neutral view while the CLI target gate remains conservative:

    moon run cmd/main -- build --target alipay --example agent_map --strict moon run cmd/main -- build --target tiktok --example agent_map --strict

    ///|
    test {
    let root = @bunnia.page([@bunnia.button("Open", "open-detail")])
    let alipay = @bunnia.generate_alipay_project(name="Adapter", root~)
    let tiktok = @bunnia.generate_tiktok_project(name="Adapter", root~)
    assert_true(alipay.files[2].path.has_suffix(".axml"))
    assert_true(tiktok.files[2].path.has_suffix(".ttml"))
    assert_eq(alipay.page.plan.node_count, tiktok.page.plan.node_count)
    }
    Use @bunnia.platform_limits(...) or @bunnia.platform_limits_for_adapter(...) to inspect component mapping, tap-event mapping, lifecycle mapping, request API mapping, and target capabilities from the same adapter boundary before choosing a generator.

    ///|
    test {
    let limits = @bunnia.platform_limits(target="wechat")
    assert_eq(limits.generator_status_id, "available")
    assert_eq(limits.generator_available, true)
    assert_eq(limits.event_mappings[0].platform_event, "bindtap")
    assert_eq(limits.request_mappings[0].platform_api, "wx.request")
    assert_true(limits.summary.contains("components=9"))
    let alipay = @bunnia.platform_limits(target="alipay")
    assert_eq(alipay.generator_status_id, "available")
    assert_eq(alipay.event_mappings[0].platform_event, "onTap")
    assert_eq(alipay.request_mappings[0].platform_api, "my.request")
    }

    For map-heavy surfaces, use @bunnia.static_scene_view_with_viewport(...) and @bunnia.plan_scene_render_viewport(...). Scene plans and build profiles report visible/total marker and region counts so large maps can stay spatially bounded. Viewported scene views keep full scene dimensions as data while rendering a viewport-sized surface with viewport-local marker, region, and overlay coordinates, so first-screen layout does not inherit the whole map size. Generic render plans and generated route manifests also report scene count, visible/total marker count, visible/total region count, scene asset count, and degraded scene count, so map pressure is visible even before product-specific profiling is wired in. Route manifests include the render-budget limits used for generation, which keeps budget failures explainable from generated output alone. @bunnia.render_budget(...) can gate visible scene marker count, visible scene region count, scene asset reference count, and degraded scene count directly, which lets strict builds catch oversized first-screen map routes without penalizing offscreen world size. WeChat generation APIs also accept explicit render budgets, so route manifests and build reports carry those render diagnostics into normal build output. For agentic pages, route initial-data bytes are also checked against the page render budget. Use @bunnia.scene_camera(...) with @bunnia.static_scene_view_with_camera(...) when pan/zoom state should be explicit, clamped to scene bounds, and updated through small camera patches.

    For agentic map surfaces, use @bunnia.scene_marker_thread_link(...), @bunnia.scene_region_thread_link(...), or the generic @bunnia.scene_thread_link(...) plus @bunnia.plan_scene_threads(...) to keep scene-subject badges measurable. Scene thread plans report visible/total links, unread pressure, orphan marker/region links, and missing open actions before the mini-app output grows. Scene-aware overlays derive badge anchors from marker centers or region centers, so agent communication stays attached to the map without product-specific positioning code. Use the viewport-aware anchored overlay and planner helpers when a large map is cameraed or clipped; they keep total thread counts visible while budgeting and rendering only badges inside the active viewport. Use @bunnia.plan_scene_surface_for_platform(...) to make the intended static/canvas/lightweight surface mode and any fallback explicit in build profiles before adding platform-specific rendering. Use @bunnia.plan_scene_visual_quality(...) for a checklist covering scene size, marker status, tap targets, asset references, unresolved assets, and degraded output. Use @bunnia.plan_scene_visual_quality_viewport(...) for cameraed or clipped maps; it checks the viewport-sized rendered surface and visible objects while the embedded render plan still reports total/visible world geometry. Use @bunnia.plan_scene_assets_with_budget(...) to identify bundled scene assets that should be deferred or moved remote when package-byte budgets are tight. Use @bunnia.plan_scene_assets_with_budget_and_policy(...) when remote assets must stay on approved domains; build profiles report remote, unapproved-remote, insecure-remote, and deferred asset counts. Build profiles also report generated scene asset counts derived from the WeChat manifest, so strict builds can compare planned package pressure with the actual route asset references emitted by the mini-app generator.

    #WeChat package policy

    Bunnia's WeChat release profile treats 2 MiB as the hard main-package limit and 1.5 MiB as the recommended operating ceiling. A build above 1.5 MiB receives the split-recommended advisory so there is room for future iteration; a build above 2 MiB fails the strict release budget. The report and generated manifest count the materialized bytes of copied assets, not the length of their copy-file: marker.

    Follow the platform packaging model supplied for MoonSuite deployments:

    • keep the main package at or below 1.5 MiB whenever practical;
    • keep every subpackage at or below 2 MiB and all subpackages at or below 30 MiB in total;
    • reserve the main package for startup routes and truly boot-critical assets;
    • move non-TabBar pages and large optional components into subpackages;
    • serve image, audio, and video libraries from approved CDN or object-storage domains, while keeping a compact local fallback for the first screen;
    • import third-party libraries by used function or module instead of bundling an entire library.

    Remote assets still require an explicit approved-domain policy, rights metadata, and a usable failure state. Subpackaging is an architectural release step rather than a way to hide oversized startup code.

    Markers carry stable data-hit-width and data-hit-height attributes, and visual quality plans flag tappable markers with hit targets below the configured minimum so map interactions stay usable on mobile.

    Use @bunnia.surface_status_badge(...) and @bunnia.surface_status_overlay(...) for loading, stale, error, retry, cancelled, or degraded state that should be visible without replacing the underlying list, dashboard, feed, or scene model.

    For backend refreshes, use @bunnia.plan_snapshot_deltas(...) to turn section updates, append-only items, and removals into bounded patches. Full snapshot replacement is still representable for bootstrap paths, but plans flag it. Build profiles report snapshot delta counts, section updates, append pressure, and full replacements so large mini-apps do not accidentally refresh whole pages. WeChat build reports, manifests, inspections, and snapshots also report update operation counts separately from update payload bytes, so many small setData keys stay visible as a speed risk even when the JSON payload is compact. Project inspections also rank and gate route-level repeated-list pressure from generated manifests, including unwindowed rows, unkeyed rows, and duplicate keys. Snapshots include first-class list, agent workflow, snapshot replacement, and map-quality pressure counters, so CI diffs can track huge-app render and interaction risk without parsing the long profile summary.

    Generate a standalone starter project with:

    moon run cmd/main -- init --name my_miniapp --module local/my_miniapp --out /tmp/my-miniapp

    The generated starter keeps agent chat and map-heavy surfaces first-class while splitting app view, agent feed, scene model, bounded updates, budget checks, backend contract, inspection/profile gates, release readiness, and WeChat generation into separate files, plus a local cmd/main build command that writes the starter's WeChat files and supports --strict diagnostic gating. The same command has an inspect mode for no-write route, backend, map, file pressure, and release-readiness checks and a snapshot mode for deterministic generated-output artifacts, plus a no-write limits mode for platform capabilities and generator status. WeChat build, inspect, snapshot, and CI-plan paths reuse Bunnia's target-support gate; Alipay/TikTok currently use generic build, inspect, snapshot, and watch paths with release-readiness preflight, while unknown targets report diagnostics before artifacts are generated. It also prints a local ci-plan with check, test, interface, format, product-neutral boundary, platform-limits, inspect, snapshot, strict build, one-shot watch commands, and the active inspection/profile/release thresholds. Its summary reports the current generated-output and gate diagnostic count. Starter tests check render budgets, scene output, bounded patches, backend visibility, release readiness, profile gates, and clean WeChat event wiring. The command also writes a local moon.work that includes the starter app and the current Bunnia checkout for pre-registry development.

    Generate the Wenyu proof slice with:

    moon run cmd/main -- --example wenyu_overview

    ///|
    test {
    let page = @bunnia.page([
    @bunnia.view([
    @bunnia.text("Demo Dashboard"),
    @bunnia.button("Open Detail", "open-detail"),
    ]),
    ])
    let plan = @bunnia.plan(page, @bunnia.wechat())
    assert_eq(plan.node_count, 5)
    }

    ///|
    test {
    let plan = @bunnia.plan_scene_assets_with_budget_and_policy(
    [
    @bunnia.remote_image_asset(
    "remote-ok", "https://cdn.example.test/tile.png",
    ),
    @bunnia.remote_image_asset(
    "remote-bad", "https://assets.example.test/tile.png",
    ),
    ],
    @bunnia.default_scene_asset_budget(),
    @bunnia.scene_asset_policy(approved_remote_domains=["cdn.example.test"]),
    )
    assert_eq(plan.remote_assets, 2)
    assert_eq(plan.unapproved_remote_asset_count, 1)
    }

    ///|
    test {
    let app = @bunnia.program(
    id="counter",
    model=0,
    view=fn(count) {
    @bunnia.page([
    @bunnia.text("Count \{count}"),
    @bunnia.button("Increment", "inc"),
    ])
    },
    update=fn(count, msg) {
    if msg == "inc" {
    @bunnia.step(model=count + 1)
    } else {
    @bunnia.step(model=count)
    }
    },
    )
    let next = @bunnia.apply(app, "inc")
    let output = @bunnia.generate_wechat_page(
    "Counter",
    @bunnia.current_view(next),
    )
    assert_true(output.wxml.contains("Count 1"))
    }

    ///|
    test {
    let trace = @bunnia.communication_trace([
    @bunnia.handoff(
    id="handoff-1",
    thread_id="thread-a",
    from_actor_id="agent-a",
    to_actor_id="operator",
    text="Please review this result.",
    open_message="open-review",
    ),
    ])
    let output = @bunnia.generate_wechat_page("Trace", @bunnia.page([trace]))
    assert_true(output.wxml.contains("bunnia-communication-handoff"))
    assert_true(output.wxml.contains("open-review"))
    }

    ///|
    test {
    let runtime = @bunnia.wechat_runtime(initial_data_json="{\"counter\":0}", event_patches=[
    @bunnia.wechat_event_patch("open-detail", [@bunnia.set_json("counter", "1")]),
    ])
    let project = @bunnia.generate_wechat_project_with_runtime(
    name="Budgeted",
    root=@bunnia.page([@bunnia.button("Open", "open-detail")]),
    runtime~,
    )
    let report = @bunnia.report_wechat_project(project, runtime)
    assert_eq(report.file_count, 10)
    assert_true(project.manifest.summary.contains("app_files=9"))
    assert_true(report.initial_data_bytes > 0)
    assert_true(report.event_patch_bytes > 0)
    }

    ///|
    test {
    let contract = @bunnia.backend_contract(id="agent-backend", endpoints=[
    @bunnia.agent_message_endpoint(
    "send-agent-message", "/agent/message", "message", "messageResult",
    ),
    @bunnia.review_decision_endpoint(
    "review-decision", "/review/decision", "review", "reviewResult",
    ),
    ])
    let plan = @bunnia.plan_backend_contract(contract)
    let effects = @bunnia.plan_backend_effects_for_platform(
    contract,
    @bunnia.wechat(),
    )
    let js = @bunnia.generate_wechat_request_adapter(contract)
    assert_eq(plan.endpoint_count, 2)
    assert_eq(effects.effect_count, 2)
    assert_true(js.contains("wx.request"))
    assert_true(!js.contains("secret"))
    }

    ///|
    test {
    let plan = @bunnia.plan_snapshot_deltas([
    @bunnia.set_snapshot_section_delta(
    "home", "buildings", "[{\"id\":\"hall\"}]",
    ),
    @bunnia.append_snapshot_item_delta(
    "home", "messages", "msg-1", "{\"id\":\"msg-1\"}",
    ),
    ])
    assert_eq(plan.section_update_count, 1)
    assert_eq(plan.append_item_count, 1)
    assert_eq(plan.full_snapshot_count, 0)
    assert_true(plan.patch_plan.total_estimated_bytes < 128)
    }

    ///|
    test {
    let assets = [@bunnia.sprite_asset("agent", "/assets/agent.png", 2048)]
    let map = @bunnia.static_scene_view(
    @bunnia.scene(
    "overview",
    @bunnia.scene_size(640, 480),
    [
    @bunnia.layer("districts", 1, [], regions=[
    @bunnia.region(
    id="district-a",
    label="District A",
    x=48,
    y=64,
    width=240,
    height=160,
    status="review",
    tap_message="select-district-a",
    ),
    ]),
    @bunnia.layer("actors", 10, [
    @bunnia.marker(
    id="actor-a",
    label="Agent A",
    x=120,
    y=180,
    status="running",
    asset_ref="agent",
    tap_message="select-actor-a",
    ),
    ]),
    ],
    assets~,
    ),
    )
    let patches = @bunnia.plan_patches([
    @bunnia.select_scene_region("overview", "district-a"),
    @bunnia.set_scene_marker_status("overview", "actor-a", "selected"),
    ])
    let output = @bunnia.generate_wechat_page("Map", @bunnia.page([map]))
    assert_true(output.wxml.contains("data-region-id=\"district-a\""))
    assert_true(output.wxml.contains("bunnia-scene-sprite"))
    assert_true(patches.total_estimated_bytes < 96)
    }

    ///|
    test {
    let map = @bunnia.scene(
    "ops-map",
    @bunnia.scene_size(640, 420),
    [
    @bunnia.layer("markers", 1, [
    @bunnia.marker(
    id="agent",
    label="Agent",
    x=120,
    y=140,
    status="running",
    tap_message="select-agent",
    asset_ref="agent",
    ),
    ]),
    ],
    assets=[@bunnia.sprite_asset("agent", "/assets/agent.png", 2048)],
    )
    let quality = @bunnia.plan_scene_visual_quality(map)
    assert_eq(quality.degraded, false)
    assert_eq(quality.diagnostics.length(), 0)
    }

    ///|
    test {
    let feed = @bunnia.message_feed([
    @bunnia.message(
    id="msg-1",
    actor_id="agent-a",
    thread_id="thread-a",
    text="Working",
    artifact_ref="artifact://result-a",
    ),
    ])
    let map = @bunnia.static_scene_view(
    @bunnia.scene("overview", @bunnia.scene_size(640, 480), [
    @bunnia.layer("actors", 10, [
    @bunnia.marker(
    id="actor-a",
    label="Agent A",
    x=120,
    y=180,
    status="running",
    tap_message="select-actor-a",
    ),
    ]),
    ]),
    )
    let output = @bunnia.generate_wechat_page("Demo", @bunnia.page([feed, map]))
    assert_true(output.wxml.contains("select-actor-a"))
    assert_true(output.js.contains("__bunnia.lastMessage"))
    }

    Actor

    ActorKind

    AgentDelta

    AgentDeltaKind

    AgentDeltaPlan

    Attr

    using @vectie/bunnia/core { type Attr }

    BackendBudget

    BackendContract

    BackendEndpoint

    BackendEndpointKind

    BackendPlan

    BackendRequest

    BackendResult

    BackendResultKind

    BackendState

    BuildProfile

    BuildProfileBudget

    BuildProfileGate

    CiPlan

    CiPlanStep

    Communication

    CommunicationBudget

    CommunicationFilter

    CommunicationKind

    CommunicationPlan

    Effect

    EffectKind

    EffectPlan

    EventBinding

    GeneratedSnapshot

    GeneratedSnapshotFile

    HttpMethod

    Message

    MiniappInspection

    MiniappInspectionBudget

    MiniappInspectionGate

    MiniappReleaseReadinessReport

    using @vectie/bunnia/tooling { type ReleaseReadinessReport as MiniappReleaseReadinessReport }

    Node

    using @vectie/bunnia/core { type Node }

    Patch

    using @vectie/bunnia/core { type Patch }

    PatchBudget

    PatchKind

    PatchPlan

    Platform

    PlatformAdapter

    PlatformComponentMapping

    PlatformEventMapping

    PlatformGeneratorStatus

    PlatformLifecycleMapping

    PlatformLimitsReport

    PlatformRequestMapping

    PlatformTargetSupport

    Program

    ProjectInspection

    ProjectInspectionBudget

    ProjectInspectionGate

    ReleaseReadinessReport

    RenderBudget

    RenderPlan

    ReviewAction

    ReviewState

    RouteInspection

    RunStatus

    ScaffoldFile

    ScaffoldPlan

    Scene

    SceneAsset

    SceneAssetBudget

    SceneAssetKind

    SceneAssetPlan

    SceneAssetPolicy

    SceneCamera

    SceneCameraBudget

    SceneCameraPlan

    SceneLayer

    SceneMarker

    SceneQualityLevel

    SceneRegion

    SceneRenderBudget

    SceneRenderMode

    SceneRenderPlan

    SceneSize

    SceneSurfacePlan

    SceneSurfacePreference

    SceneThreadBudget

    SceneThreadPlan

    SceneViewport

    SceneVisualQualityBudget

    SceneVisualQualityPlan

    SnapshotDelta

    SnapshotDeltaKind

    SnapshotDeltaPlan

    SurfaceStatus

    SurfaceStatusKind

    Thread

    ToolResultBudget

    ToolResultCard

    ToolResultPlan

    WechatManifestSceneAsset

    WechatProjectManifest

    actor

    fn actor(id~ : String, label~ : String, kind? :
    ActorKind
    ) ->
    Actor

    agent_cancel_endpoint

    fn agent_cancel_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
    BackendEndpoint

    agent_delta_kind_id

    fn agent_delta_kind_id(kind :
    AgentDeltaKind
    ) -> String

    agent_message_endpoint

    fn agent_message_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
    BackendEndpoint

    agent_retry_endpoint

    fn agent_retry_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
    BackendEndpoint

    agent_stream_endpoint

    fn agent_stream_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
    BackendEndpoint

    all_communication_filter

    anchored_scene_thread_overlay

    anchored_scene_thread_overlay_with_viewport

    append_communication_delta

    fn append_communication_delta(target_path : String, item :
    Communication
    ) ->
    AgentDelta

    append_json

    fn append_json(path : String, value_json : String) ->
    Patch

    append_message_delta

    fn append_message_delta(target_path : String, item :
    Message
    ) ->
    AgentDelta

    fn append_scene_thread_link(target_path : String, link :
    SceneThreadLink
    ) ->
    Patch

    append_snapshot_item_delta

    fn append_snapshot_item_delta(scope : String, section : String, item_id : String, value_json : String) ->
    SnapshotDelta

    append_stream_chunk_delta

    fn append_stream_chunk_delta(target_path : String, chunk_id : String, text : String, status? :
    RunStatus
    ) ->
    AgentDelta

    apply

    fn[Model, Msg] apply(input :
    Program
    [Model, Msg], message : Msg) ->
    Program
    [Model, Msg]

    approval

    fn approval(id~ : String, thread_id~ : String, from_actor_id~ : String, to_actor_id~ : String, text~ : String, artifact_ref? : String, open_message? : String) ->
    Communication

    attr

    fn attr(name : String, value : String) ->
    Attr

    backend_budget

    fn backend_budget(max_endpoints~ : Int, max_streaming~ : Int, max_review_required~ : Int) ->
    BackendBudget

    backend_contract

    fn backend_contract(id~ : String, base_url_key? : String, session_token_key? : String, session_header_key? : String, endpoints~ : Array[
    BackendEndpoint
    ]) ->
    BackendContract

    backend_contract_effects

    backend_endpoint

    fn backend_endpoint(id~ : String, kind~ :
    BackendEndpointKind
    , http_method~ :
    HttpMethod
    , path~ : String, payload_key? : String, response_key? : String, timeout_ms? : Int, streaming? : Bool, requires_review? : Bool) ->
    BackendEndpoint

    backend_endpoint_kind_id

    fn backend_endpoint_kind_id(kind :
    BackendEndpointKind
    ) -> String

    backend_error_patch

    fn backend_error_patch(scope : String, message : String) ->
    Patch

    backend_failure

    backend_malformed

    backend_request

    fn backend_request(id~ : String, endpoint~ :
    BackendEndpoint
    , payload_json? : String, replay_key? : String) ->
    BackendRequest

    backend_request_patches

    backend_response_patch

    fn backend_response_patch(scope : String, value_json : String) ->
    Patch

    backend_result_cancelled

    backend_result_failure

    backend_result_kind_id

    fn backend_result_kind_id(kind :
    BackendResultKind
    ) -> String

    backend_result_malformed

    backend_result_patches

    backend_result_success

    backend_result_timeout

    backend_state_cancelled

    fn backend_state_cancelled() ->
    BackendState

    backend_state_failed

    backend_state_id

    fn backend_state_id(state :
    BackendState
    ) -> String

    backend_state_idle

    backend_state_loading

    backend_state_malformed

    fn backend_state_malformed() ->
    BackendState

    backend_state_patch

    fn backend_state_patch(scope : String, state :
    BackendState
    ) ->
    Patch

    backend_state_ready

    backend_state_stale

    backend_state_timeout

    backend_success

    backend_timeout

    broadcast

    fn broadcast(id~ : String, thread_id~ : String, from_actor_id~ : String, text~ : String, open_message? : String) ->
    Communication

    build_profile_budget

    fn build_profile_budget(max_route_diagnostic_routes~ : Int, max_route_diagnostics~ : Int, max_unwindowed_list_children~ : Int, max_unkeyed_list_children~ : Int, max_duplicate_list_keys~ : Int, max_communication_unresolved_reviews~ : Int, max_tool_result_missing_acks~ : Int, max_agent_duplicate_stream_chunks~ : Int, max_snapshot_full_replaces~ : Int, max_scene_thread_orphans~ : Int, max_scene_camera_clamped~ : Int, max_scene_surface_fallbacks~ : Int, max_scene_insecure_remote_assets~ : Int, max_scene_unapproved_remote_assets~ : Int, max_scene_deferred_assets~ : Int, max_scene_quality_issues~ : Int, max_degraded_scenes~ : Int) ->
    BuildProfileBudget

    build_profile_budget_for_profile

    fn build_profile_budget_for_profile(name : String) ->
    BuildProfileBudget

    button

    fn button(label : String, message : String) ->
    Node

    cancel

    fn cancel(id : String, target : String) ->
    Effect

    canvas

    fn canvas(canvas_id : String) ->
    Node

    ci_plan

    fn ci_plan(target? : String, budget_profile? : String, render_budget_profile? : String, examples? : Array[String], snapshot_dir? : String, post_build_steps? : Array[
    CiPlanStep
    ]) ->
    CiPlan

    ci_plan_shell_script

    fn ci_plan_shell_script(plan :
    CiPlan
    ) -> String

    ci_plan_step

    fn ci_plan_step(name : String, command : String, purpose : String) ->
    CiPlanStep

    class_name

    fn class_name(value : String) ->
    Attr

    cloud_function

    fn cloud_function(id : String, target : String, payload_key : String) ->
    Effect

    communication

    fn communication(id~ : String, thread_id~ : String, kind~ :
    CommunicationKind
    , from_actor_id~ : String, to_actor_id? : String, text~ : String, artifact_ref? : String, timestamp? : String, status? :
    RunStatus
    , open_message? : String) ->
    Communication

    communication_approval

    communication_broadcast

    communication_budget

    fn communication_budget(max_visible_count? : Int, max_review_request_count? : Int, max_unresolved_review_count? : Int, max_artifact_ref_count? : Int) ->
    CommunicationBudget

    communication_filter

    fn communication_filter(thread_id? : String, actor_id? : String, kind_id? : String, include_resolved_reviews? : Bool) ->
    CommunicationFilter

    communication_handoff

    communication_kind_id

    fn communication_kind_id(kind :
    CommunicationKind
    ) -> String

    communication_message

    communication_recovery_notice

    fn communication_recovery_notice() ->
    CommunicationKind

    communication_review_request

    fn communication_review_request() ->
    CommunicationKind

    communication_tool_result

    communication_trace

    current_view

    fn[Model, Msg] current_view(input :
    Program
    [Model, Msg]) ->
    Node

    data

    fn data(name : String, value : String) ->
    Attr

    default_backend_budget

    default_communication_budget

    default_patch_budget

    fn default_patch_budget() ->
    PatchBudget

    default_render_budget

    fn default_render_budget() ->
    RenderBudget

    default_scene_asset_budget

    default_scene_asset_policy

    default_scene_camera_budget

    default_scene_render_budget

    default_scene_thread_budget

    default_scene_visual_quality_budget

    default_tool_result_budget

    default_wechat_build_budget

    default_wechat_runtime

    effect

    fn effect(id~ : String, kind~ :
    EffectKind
    , target~ : String, payload_key? : String, message? : String) ->
    Effect

    effect_kind_id

    fn effect_kind_id(kind :
    EffectKind
    ) -> String

    endpoint_agent_message_send

    endpoint_agent_operation_cancel

    endpoint_agent_operation_retry

    endpoint_agent_run_status

    endpoint_effect

    endpoint_handoff_submit

    endpoint_operator_submit

    endpoint_review_decision

    endpoint_snapshot_load

    endpoint_status_load

    endpoint_thread_load

    event

    fn event(event : String, message : String) ->
    EventBinding

    form

    fn form(submit_message : String, children : Array[
    Node
    ]) ->
    Node

    generate_alipay_page

    generate_alipay_project

    fn generate_alipay_project(name~ : String, route? : String, root~ :
    Node
    ) ->
    MiniappProject

    generate_miniapp_page

    generate_miniapp_page_with_budget

    generate_miniapp_project

    fn generate_miniapp_project(name~ : String, route? : String, root~ :
    Node
    , platform~ :
    Platform
    ) ->
    MiniappProject

    generate_miniapp_project_with_budget

    fn generate_miniapp_project_with_budget(name~ : String, route? : String, root~ :
    Node
    , platform~ :
    Platform
    , render_budget~ :
    RenderBudget
    ) ->
    MiniappProject

    generate_tiktok_page

    generate_tiktok_project

    fn generate_tiktok_project(name~ : String, route? : String, root~ :
    Node
    ) ->
    MiniappProject

    generate_wechat_page

    generate_wechat_page_with_runtime

    generate_wechat_page_with_runtime_and_budget

    generate_wechat_project

    fn generate_wechat_project(name~ : String, route? : String, root~ :
    Node
    ) ->
    WechatProject

    generate_wechat_project_from_pages

    generate_wechat_project_from_pages_with_backend

    generate_wechat_project_with_runtime

    fn generate_wechat_project_with_runtime(name~ : String, route? : String, root~ :
    Node
    , runtime~ :
    WechatRuntime
    ) ->
    WechatProject

    generate_wechat_project_with_runtime_and_backend

    fn generate_wechat_project_with_runtime_and_backend(name~ : String, route? : String, root~ :
    Node
    , runtime~ :
    WechatRuntime
    , backend_contract~ :
    BackendContract
    ) ->
    WechatProject

    generate_wechat_project_with_runtime_and_budget

    fn generate_wechat_project_with_runtime_and_budget(name~ : String, route? : String, root~ :
    Node
    , runtime~ :
    WechatRuntime
    , render_budget~ :
    RenderBudget
    ) ->
    WechatProject

    generate_wechat_project_with_runtime_and_budget_and_backend

    fn generate_wechat_project_with_runtime_and_budget_and_backend(name~ : String, route? : String, root~ :
    Node
    , runtime~ :
    WechatRuntime
    , render_budget~ :
    RenderBudget
    , backend_contract~ :
    BackendContract
    ) ->
    WechatProject

    generate_wechat_request_adapter

    fn generate_wechat_request_adapter(contract :
    BackendContract
    ) -> String

    generate_wechat_runtime_js

    fn generate_wechat_runtime_js() -> String

    generate_wechat_set_data_call

    fn generate_wechat_set_data_call(patches : Array[
    Patch
    ]) -> String

    generic_endpoint

    fn generic_endpoint(id : String, path : String, http_method :
    HttpMethod
    , payload_key? : String, response_key? : String) ->
    BackendEndpoint

    handoff

    fn handoff(id~ : String, thread_id~ : String, from_actor_id~ : String, to_actor_id~ : String, text~ : String, open_message? : String) ->
    Communication

    handoff_submit_endpoint

    fn handoff_submit_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
    BackendEndpoint

    http_method_id

    fn http_method_id(input :
    HttpMethod
    ) -> String

    fn id(value : String) ->
    Attr

    image

    fn image(src : String, alt : String) ->
    Node

    image_asset

    fn image_asset(id : String, src : String, estimated_bytes : Int) ->
    SceneAsset

    input

    fn input(name~ : String, value? : String, input_message? : String) ->
    Node

    inspect_miniapp_project

    fn inspect_miniapp_project(target~ : String, example~ : String, project :
    MiniappProject
    ) ->
    MiniappInspection

    inspection_budget

    fn inspection_budget(max_route_risk_score~ : Int, max_update_payload_bytes~ : Int, max_update_operations~ : Int, max_unwindowed_list_children~ : Int, max_unkeyed_list_children~ : Int, max_duplicate_list_keys~ : Int, max_backend_events~ : Int, max_backend_streams~ : Int, max_backend_reviews~ : Int, max_backend_cancels~ : Int, max_backend_retries~ : Int, max_scene_assets~ : Int, max_scene_remote_assets~ : Int, max_scene_package_bytes~ : Int) ->
    ProjectInspectionBudget

    inspection_budget_for_profile

    fn inspection_budget_for_profile(name : String) ->
    ProjectInspectionBudget

    is_named_budget_profile

    fn is_named_budget_profile(name : String) -> Bool

    keyed

    list

    fn[Item] list(items : Array[Item], render : (Item) ->
    Node
    ) ->
    Node

    login

    fn login(id : String, target : String) ->
    Effect

    marker

    fn marker(id~ : String, label~ : String, x~ : Int, y~ : Int, status? : String, tap_message? : String, asset_ref? : String, hit_width? : Int, hit_height? : Int) ->
    SceneMarker

    max_depth

    fn max_depth(root :
    Node
    ) -> Int

    message

    fn message(id~ : String, actor_id~ : String, thread_id~ : String, text~ : String, artifact_ref? : String, status? :
    RunStatus
    ) ->
    Message

    message_event

    fn message_event(id~ : String, thread_id~ : String, from_actor_id~ : String, text~ : String, artifact_ref? : String, open_message? : String) ->
    Communication

    miniapp_inspection_budget

    fn miniapp_inspection_budget(max_pages~ : Int, max_files~ : Int, max_total_bytes~ : Int, max_route_diagnostic_routes~ : Int, max_route_diagnostics~ : Int, max_nodes~ : Int, max_depth~ : Int, max_events~ : Int, max_scene_markers~ : Int, max_scene_regions~ : Int, max_scene_assets~ : Int) ->
    MiniappInspectionBudget

    miniapp_inspection_budget_for_profile

    fn miniapp_inspection_budget_for_profile(name : String) ->
    MiniappInspectionBudget

    miniapp_release_readiness_report

    fn navigate(id : String, target : String) ->
    Effect

    node

    fn node(kind~ : String, key? : String, attrs? : Array[
    Attr
    ], events? : Array[
    EventBinding
    ], children? : Array[
    Node
    ], text? : String) ->
    Node

    node_count

    fn node_count(root :
    Node
    ) -> Int

    operator_submit_endpoint

    fn operator_submit_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
    BackendEndpoint

    patch_budget

    fn patch_budget(max_patches~ : Int, max_patch_bytes~ : Int) ->
    PatchBudget

    plan_backend_effects_for_platform

    plan_effects_for_platform

    plan_patches_with_budget

    plan_scene_visual_quality

    platform_adapter

    fn platform_adapter(platform~ :
    Platform
    , id~ : String, page_component~ : String, tap_event~ : String, component_prefix? : String, app_launch_lifecycle? : String, page_load_lifecycle? : String, page_ready_lifecycle? : String, request_api? : String, supports_canvas? : Bool, supports_cloud? : Bool, supports_stream? : Bool) ->
    PlatformAdapter

    platform_generator_available

    fn platform_generator_available(status :
    PlatformGeneratorStatus
    ) -> Bool

    platform_generator_status_id

    fn platform_generator_status_id(status :
    PlatformGeneratorStatus
    ) -> String

    platform_id

    fn platform_id(platform :
    Platform
    ) -> String

    platform_label

    fn platform_label(platform :
    Platform
    ) -> String

    platform_limits

    platform_limits_for_adapter

    platform_target_support

    fn platform_target_support(target? : String) ->
    PlatformTargetSupport

    platform_target_support_for_adapter

    fn platform_target_support_for_adapter(adapter :
    PlatformAdapter
    , generator_available? : Bool) ->
    PlatformTargetSupport

    prefer_canvas_surface

    prefer_lightweight_surface

    prefer_static_surface

    program

    fn[Model, Msg] program(id~ : String, model~ : Model, view~ : (Model) ->
    Node
    , update~ : (Model, Msg) ->
    Step
    [Model], init_effects? : Array[
    Effect
    ]) ->
    Program
    [Model, Msg]

    recovery_notice

    fn recovery_notice(id~ : String, thread_id~ : String, from_actor_id~ : String, text~ : String, open_message? : String) ->
    Communication

    region

    fn region(id~ : String, label~ : String, x~ : Int, y~ : Int, width~ : Int, height~ : Int, status? : String, tap_message? : String) ->
    SceneRegion

    remote_image_asset

    fn remote_image_asset(id : String, src : String) ->
    SceneAsset

    remove_path

    fn remove_path(path : String) ->
    Patch

    remove_snapshot_section_delta

    fn remove_snapshot_section_delta(scope : String, section : String) ->
    SnapshotDelta

    render_budget

    fn render_budget(max_nodes~ : Int, max_depth~ : Int, max_events~ : Int, max_initial_data_bytes~ : Int, max_unwindowed_list_children? : Int, max_scene_markers? : Int, max_scene_regions? : Int, max_scene_assets? : Int, max_degraded_scenes? : Int) ->
    RenderBudget

    render_budget_for_profile

    fn render_budget_for_profile(name : String) ->
    RenderBudget

    replace_snapshot_delta

    fn replace_snapshot_delta(scope : String, value_json : String) ->
    SnapshotDelta

    request

    fn request(id : String, target : String, payload_key : String) ->
    Effect

    retry

    fn retry(id : String, target : String) ->
    Effect

    review_action

    fn review_action(id~ : String, label~ : String, approve_message~ : String, reject_message~ : String, state? :
    ReviewState
    ) ->
    ReviewAction

    review_action_enabled

    fn review_action_enabled(action :
    ReviewAction
    ) -> Bool

    review_approved

    review_cancelled

    review_decision_endpoint

    fn review_decision_endpoint(id : String, path : String, payload_key : String, response_key : String) ->
    BackendEndpoint

    review_failed

    review_not_required

    review_pending

    review_rejected

    review_request

    fn review_request(id~ : String, thread_id~ : String, from_actor_id~ : String, to_actor_id~ : String, text~ : String, artifact_ref? : String, open_message? : String) ->
    Communication

    review_state_id

    fn review_state_id(state :
    ReviewState
    ) -> String

    run_cancelled

    run_failed

    run_running

    run_status_id

    fn run_status_id(status :
    RunStatus
    ) -> String

    run_waiting_review

    fn run_waiting_review() ->
    RunStatus

    scaffold_project

    fn scaffold_project(name~ : String, module_name? : String) ->
    ScaffoldPlan

    scene_asset

    fn scene_asset(id~ : String, kind~ :
    SceneAssetKind
    , src~ : String, estimated_bytes? : Int, remote? : Bool) ->
    SceneAsset

    scene_asset_budget

    fn scene_asset_budget(max_assets~ : Int, max_package_bytes~ : Int, max_remote_assets~ : Int) ->
    SceneAssetBudget

    scene_asset_image

    scene_asset_kind_id

    fn scene_asset_kind_id(kind :
    SceneAssetKind
    ) -> String

    scene_asset_policy

    fn scene_asset_policy(approved_remote_domains~ : Array[String], require_https? : Bool) ->
    SceneAssetPolicy

    scene_asset_remote_image

    fn scene_asset_remote_image() ->
    SceneAssetKind

    scene_asset_sprite

    scene_asset_tile

    scene_camera

    fn scene_camera(scene_id~ : String, x~ : Int, y~ : Int, width~ : Int, height~ : Int, zoom_percent? : Int) ->
    SceneCamera

    scene_camera_budget

    fn scene_camera_budget(min_zoom_percent? : Int, max_zoom_percent? : Int, min_viewport_width? : Int, min_viewport_height? : Int) ->
    SceneCameraBudget

    scene_camera_from_viewport

    fn scene_camera_from_viewport(scene_id : String, viewport :
    SceneViewport
    , zoom_percent? : Int) ->
    SceneCamera

    scene_marker_count

    fn scene_marker_count(input :
    Scene
    ) -> Int

    fn scene_marker_thread_link(id~ : String, scene_id~ : String, marker_id~ : String, thread_id~ : String, subject_ref? : String, status? : String, unread_count? : Int, open_message? : String) ->
    SceneThreadLink

    scene_mode_canvas_surface

    fn scene_mode_canvas_surface() ->
    SceneRenderMode

    scene_mode_lightweight_markup

    fn scene_mode_lightweight_markup() ->
    SceneRenderMode

    scene_mode_static_markup

    scene_quality_balanced

    scene_quality_full

    scene_quality_id

    fn scene_quality_id(quality :
    SceneQualityLevel
    ) -> String

    scene_quality_lightweight

    scene_region_count

    fn scene_region_count(input :
    Scene
    ) -> Int

    fn scene_region_thread_link(id~ : String, scene_id~ : String, region_id~ : String, thread_id~ : String, subject_ref? : String, status? : String, unread_count? : Int, open_message? : String) ->
    SceneThreadLink

    scene_render_budget

    fn scene_render_budget(max_layers~ : Int, max_markers~ : Int, max_static_assets~ : Int, max_regions? : Int) ->
    SceneRenderBudget

    scene_render_mode_id

    fn scene_render_mode_id(mode :
    SceneRenderMode
    ) -> String

    scene_size

    fn scene_size(width : Int, height : Int) ->
    SceneSize

    scene_surface_preference_id

    fn scene_surface_preference_id(preference :
    SceneSurfacePreference
    ) -> String

    scene_thread_budget

    fn scene_thread_budget(max_visible_links? : Int, max_unread_total? : Int, max_orphan_links? : Int, max_links_without_open_message? : Int) ->
    SceneThreadBudget

    fn scene_thread_link(id~ : String, scene_id~ : String, subject_kind~ : String, subject_id~ : String, thread_id~ : String, subject_ref? : String, status? : String, unread_count? : Int, open_message? : String) ->
    SceneThreadLink

    scene_thread_overlay

    scene_viewport

    fn scene_viewport(x~ : Int, y~ : Int, width~ : Int, height~ : Int) ->
    SceneViewport

    scene_visible_marker_count

    fn scene_visible_marker_count(input :
    Scene
    , viewport :
    SceneViewport
    ) -> Int

    scene_visible_region_count

    fn scene_visible_region_count(input :
    Scene
    , viewport :
    SceneViewport
    ) -> Int

    scene_visual_quality_budget

    fn scene_visual_quality_budget(min_width~ : Int, min_height~ : Int, max_markers_without_status~ : Int, max_markers_without_tap~ : Int, max_markers_without_asset_ref~ : Int, max_unresolved_asset_refs~ : Int, max_regions_without_status? : Int, max_regions_without_tap? : Int, min_hit_width? : Int, min_hit_height? : Int, max_small_hit_targets? : Int) ->
    SceneVisualQualityBudget

    scroll_view

    select_scene_marker

    fn select_scene_marker(scene_id : String, marker_id : String) ->
    Patch

    select_scene_marker_thread

    fn select_scene_marker_thread(scene_id : String, marker_id : String, thread_id : String) ->
    Patch

    select_scene_region

    fn select_scene_region(scene_id : String, region_id : String) ->
    Patch

    select_scene_region_thread

    fn select_scene_region_thread(scene_id : String, region_id : String, thread_id : String) ->
    Patch

    select_scene_thread

    fn select_scene_thread(scene_id : String, subject_kind : String, subject_id : String, thread_id : String) ->
    Patch

    set_json

    fn set_json(path : String, value_json : String) ->
    Patch

    set_review_state_delta

    fn set_review_state_delta(target_path : String, state :
    ReviewState
    ) ->
    AgentDelta

    set_run_status_delta

    fn set_run_status_delta(target_path : String, status :
    RunStatus
    ) ->
    AgentDelta

    set_scene_camera

    fn set_scene_camera(scene_id : String, camera :
    SceneCamera
    ) ->
    Patch

    set_scene_camera_position

    fn set_scene_camera_position(scene_id : String, x : Int, y : Int) ->
    Patch

    set_scene_camera_viewport

    fn set_scene_camera_viewport(scene_id : String, viewport :
    SceneViewport
    ) ->
    Patch

    set_scene_camera_zoom

    fn set_scene_camera_zoom(scene_id : String, zoom_percent : Int) ->
    Patch

    set_scene_marker_status

    fn set_scene_marker_status(scene_id : String, marker_id : String, status : String) ->
    Patch

    set_scene_region_status

    fn set_scene_region_status(scene_id : String, region_id : String, status : String) ->
    Patch

    set_scene_thread_status

    fn set_scene_thread_status(scene_id : String, thread_id : String, status : String) ->
    Patch

    set_scene_thread_unread

    fn set_scene_thread_unread(scene_id : String, thread_id : String, unread_count : Int) ->
    Patch

    set_snapshot_section_delta

    fn set_snapshot_section_delta(scope : String, section : String, value_json : String) ->
    SnapshotDelta

    set_stream_chunk_delta

    fn set_stream_chunk_delta(target_path : String, chunk_id : String, text : String, status? :
    RunStatus
    ) ->
    AgentDelta

    set_string

    fn set_string(path : String, value : String) ->
    Patch

    share

    fn share(id : String, target : String) ->
    Effect

    snapshot_delta_kind_id

    fn snapshot_delta_kind_id(kind :
    SnapshotDeltaKind
    ) -> String

    snapshot_load_endpoint

    fn snapshot_load_endpoint(id : String, path : String, response_key : String) ->
    BackendEndpoint

    snapshot_miniapp_project

    snapshot_wechat_project

    snapshot_wechat_project_with_report

    fn snapshot_wechat_project_with_report(target~ : String, example~ : String, project :
    WechatProject
    , report :
    WechatBuildReport
    , profile :
    BuildProfile
    , budget_profile? : String, render_budget_profile? : String) ->
    GeneratedSnapshot

    sprite_asset

    fn sprite_asset(id : String, src : String, estimated_bytes : Int) ->
    SceneAsset

    static_scene_view

    static_scene_view_with_budget

    static_scene_with_windowed_threads

    fn static_scene_with_windowed_threads(input :
    Scene
    , links : Array[
    SceneThreadLink
    ], total_count~ : Int, offset? : Int) ->
    Node

    status_load_endpoint

    fn status_load_endpoint(id : String, path : String, response_key : String) ->
    BackendEndpoint

    step

    fn[Model] step(model~ : Model, effects? : Array[
    Effect
    ], patches? : Array[
    Patch
    ]) ->
    Step
    [Model]

    step_patches

    storage

    fn storage(id : String, target : String, payload_key : String) ->
    Effect

    stream

    fn stream(id : String, target : String, payload_key : String) ->
    Effect

    supported_platforms

    fn supported_platforms() -> Array[
    Platform
    ]

    surface_cancelled

    fn surface_cancelled(label? : String, detail? : String, action_message? : String) ->
    SurfaceStatus

    surface_degraded

    fn surface_degraded(label? : String, detail? : String, action_message? : String) ->
    SurfaceStatus

    surface_error

    fn surface_error(label? : String, detail? : String, action_message? : String) ->
    SurfaceStatus

    surface_loading

    fn surface_loading(label? : String, detail? : String) ->
    SurfaceStatus

    surface_ready

    fn surface_ready(label? : String, detail? : String) ->
    SurfaceStatus

    surface_retry

    fn surface_retry(label? : String, detail? : String, action_message? : String) ->
    SurfaceStatus

    surface_stale

    fn surface_stale(label? : String, detail? : String, action_message? : String) ->
    SurfaceStatus

    surface_status

    fn surface_status(kind~ :
    SurfaceStatusKind
    , label~ : String, detail? : String, action_message? : String) ->
    SurfaceStatus

    surface_status_badge

    surface_status_cancelled

    surface_status_degraded

    surface_status_error

    surface_status_kind_id

    fn surface_status_kind_id(kind :
    SurfaceStatusKind
    ) -> String

    surface_status_loading

    surface_status_overlay

    surface_status_ready

    surface_status_retry

    surface_status_stale

    text

    fn text(value : String) ->
    Node

    thread

    fn thread(id~ : String, title~ : String, owner_actor_id~ : String, subject_ref? : String, status? :
    RunStatus
    ) ->
    Thread

    thread_load_endpoint

    fn thread_load_endpoint(id : String, path : String, response_key : String) ->
    BackendEndpoint

    tile_asset

    fn tile_asset(id : String, src : String, estimated_bytes : Int) ->
    SceneAsset

    tool_ack_endpoint

    fn tool_ack_endpoint(id : String, path : String, payload_key : String) ->
    BackendEndpoint

    tool_result

    fn tool_result(id~ : String, thread_id~ : String, from_actor_id~ : String, text~ : String, artifact_ref~ : String, open_message? : String) ->
    Communication

    tool_result_budget

    fn tool_result_budget(max_visible_count? : Int, max_pending_ack_count? : Int, max_missing_ack_count? : Int, max_artifact_ref_count? : Int) ->
    ToolResultBudget

    tool_result_card

    fn tool_result_card(id~ : String, tool_name~ : String, title~ : String, summary~ : String, artifact_ref? : String, status? :
    RunStatus
    , open_message? : String, acknowledge_message? : String) ->
    ToolResultCard

    tool_result_card_list

    tool_result_card_view

    wechat_build_budget

    fn wechat_build_budget(max_pages~ : Int, max_files~ : Int, max_total_bytes~ : Int, max_wxml_bytes~ : Int, max_wxss_bytes~ : Int, max_js_bytes~ : Int, max_initial_data_bytes~ : Int, max_event_patch_bytes~ : Int, max_event_patch_operations~ : Int, max_page_first_screen_bytes~ : Int, max_page_update_payload_bytes~ : Int, max_page_update_operations~ : Int) ->
    WechatBuildBudget

    wechat_build_budget_for_profile

    fn wechat_build_budget_for_profile(name : String) ->
    WechatBuildBudget

    wechat_event_patch

    wechat_page_with_wxss

    wechat_runtime

    fn wechat_runtime(initial_data_json? : String, event_patches? : Array[
    WechatEventPatch
    ], page_methods_js? : String) ->
    WechatRuntime

    when

    fn when(condition : Bool, child :
    Node
    ) ->
    Node

    windowed_anchored_scene_thread_overlay

    fn windowed_anchored_scene_thread_overlay(input :
    Scene
    , links : Array[
    SceneThreadLink
    ], total_count~ : Int, offset? : Int) ->
    Node

    windowed_anchored_scene_thread_overlay_with_viewport

    fn windowed_anchored_scene_thread_overlay_with_viewport(input :
    Scene
    , viewport :
    SceneViewport
    , links : Array[
    SceneThreadLink
    ], total_count~ : Int, offset? : Int) ->
    Node

    windowed_communication_trace

    fn windowed_communication_trace(items : Array[
    Communication
    ], total_count~ : Int, offset? : Int) ->
    Node

    windowed_list

    fn[Item] windowed_list(items : Array[Item], total_count~ : Int, offset? : Int, render~ : (Item) ->
    Node
    ) ->
    Node

    windowed_message_feed

    fn windowed_message_feed(messages : Array[
    Message
    ], total_count~ : Int, offset? : Int) ->
    Node

    windowed_scene_thread_overlay

    fn windowed_scene_thread_overlay(links : Array[
    SceneThreadLink
    ], total_count~ : Int, offset? : Int) ->
    Node

    windowed_tool_result_card_list

    fn windowed_tool_result_card_list(cards : Array[
    ToolResultCard
    ], total_count~ : Int, offset? : Int) ->
    Node

    Source Files