diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b5dd783..574e38b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,6 +18,28 @@ jobs: env: PYTHONFAULTHANDLER: "1" + web: + name: Browser UI + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: astral-sh/setup-uv@v5 + - uses: pnpm/action-setup@v4 + with: + version: 10.17.1 + - run: uv sync --all-extras + - run: pnpm install --frozen-lockfile + working-directory: web/operator + - run: make web-proto + - run: make web-test + - run: make web-build + - uses: browser-actions/setup-chrome@v2 + id: chrome + - run: make web-bench + env: + CHROME_BIN: ${{ steps.chrome.outputs.chrome-path }} + - run: git diff --exit-code -- src/runtime/operator/proto web/operator/src/generated src/runtime/operator/web_assets + ray: name: Ray tests runs-on: ubuntu-latest diff --git a/.gitignore b/.gitignore index 7ababa5..23e7662 100644 --- a/.gitignore +++ b/.gitignore @@ -113,3 +113,5 @@ trampoline_ai_transform presentation_artifacts/ examples/customer_feedback_review/artifacts/ __marimo__ + +.vite diff --git a/ARCHITECTURE.md b/ARCHITECTURE.md index 3b8c168..2401e6a 100644 --- a/ARCHITECTURE.md +++ b/ARCHITECTURE.md @@ -416,7 +416,7 @@ only for the selected run. Control requests travel back through the provider. The operator exposes these main RPCs through `OperatorService`: -- `ListFlows` returns discovered flows. +- `GetCatalog` returns discovered workflows and scan-target metadata. - `StartRun` starts a new workflow run; caller-owned IDs are limited to 256 UTF-8 bytes so retained summaries stay bounded. - `CancelRun` requests cancellation for a run. @@ -429,7 +429,7 @@ The operator exposes these main RPCs through `OperatorService`: operator-assigned retention cursor; source-local event sequences remain in the fetched detail body. - `ReadTrace` and `ReadDetail` stream bounded chunks for immutable detail bodies. -- `StreamRunUpdates` replays typed changes under an operator-instance epoch. +- `StreamOperatorUpdates` replays typed changes under an operator-instance epoch. Stale cursors, restarts, and slow-consumer overflow require an explicit structural reset. diff --git a/CHANGELOG.md b/CHANGELOG.md index e89c9ae..9531b8e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,53 @@ ## Unreleased +### Operator web interface + +- Added an opt-in local React operator interface (`ava operator --web`) with + workflow discovery, live DAG replacement, immutable historical run canvases, + launch/cancel controls, logs, and demand-loaded agent evidence. +- Added a same-process binary gRPC-Web listener and packaged browser assets. + Loopback remains the default; non-loopback binding requires the explicit + `--web-trusted-proxy` acknowledgement. +- Run topology now retains only versioned agent input/output field schemas, + while bounded trace descriptors expose stable PredictRLM header, usage, and + telemetry metadata without embedding declaration instructions or complete + trace bodies in structural snapshots. +- Unchanged discovery results no longer advance catalog revisions, and the web UI + retains workflow/run navigation on narrow viewports with accessible input and + repeated-node labels plus WCAG AA secondary-text contrast. +- Workflow cards now show contained typed field lists while declarations remain in the inspector. + Canvases retain depth-aware edge routing, live durations, stronger execution states, and `Run` + labels. +- Agent steps now use an explicit DAG-card label and accent, including historical + runs classified from their retained agent field schemas. +- Successful and failed nodes retain their neutral borders; only their titles + and status labels use the corresponding outcome color. +- The current workflow canvas uses React Flow's neutral dotted blueprint field; + historical run canvases retain their separate neutral presentation. +- Run logs now render bounded ANSI SGR color and text-style sequences without + interpreting log content as HTML. +- Node-scoped run logs now retain canonical node IDs, including repeated-node + suffixes, so selecting a log node preserves its filtered records. +- Starting a workflow now navigates directly to its retained run snapshot as + soon as the operator publishes the run ID. +- Agent steps now default PredictRLM to quiet execution; workflows and + individual steps can explicitly opt into verbose trace logs. +- Zoomed-out run nodes center their titles while preserving a larger, + card-corner duration label. +- Failed DAG cards now show status only; inspect their retained logs for error detail. +- Retained run canvases now include a `Current workflow` control that returns + directly to the live workflow view. +- Explorer collapse and restore controls now stay at the pane edge, and Explorer and inspector + panes are independently resizable. Retained inputs, outputs, and traces use bounded progressive + JSON with content-sized key columns, while logs use a record-separated continuous-text view + without hidden unbounded DOM. +- Large-run hydration is now summary-first, cancellable, incrementally paged, and + bounded across browser queues, descriptor windows, detail caches, and virtualized + DOM rendering. `make web-bench` covers 10,000 retained runs in real Chromium. +- Added `ava operator --log-level` and explicit source-watcher and hot-reload + lifecycle logs for successful, unchanged, and failed catalog refreshes. + ### Operator transport - Operator streams now replay bounded, typed run updates under an instance epoch diff --git a/Makefile b/Makefile index f1d562e..6d812db 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: test test-cov test-cov-html lint format precommit-check check smoke-test tui-bench proto brand install clean +.PHONY: test test-cov test-cov-html lint format precommit-check check smoke-test tui-bench proto brand install clean web-bench # Run tests with every supported executor/storage extra installed. test: @@ -43,6 +43,22 @@ proto: perl -pi -e 's/^import operator_pb2 as operator__pb2$$/from . import operator_pb2 as operator__pb2/' \ src/runtime/operator/proto/operator_pb2_grpc.py +# Regenerate the checked-in TypeScript operator client. +web-proto: + cd web/operator && pnpm generate + +# Build the packaged browser interface. +web-build: + cd web/operator && pnpm build + +# Run browser projection and component tests. +web-test: + cd web/operator && pnpm test + +# Run the Vitest volume gate followed by the Node-managed real-Chromium virtualizer gate. +web-bench: + cd web/operator && pnpm benchmark + # Build checked-in brand image artifacts from the Three.js source HTML. brand: node docs/assets/brand/source/export-brand-assets.mjs diff --git a/README.md b/README.md index 45d973b..2268b36 100644 --- a/README.md +++ b/README.md @@ -378,6 +378,29 @@ ava operator --flows path/to/flows --port 7433 ava tui --connect localhost:7433 ``` +For a browser interface backed by the same operator, enable the loopback web +listener: + +```bash +ava operator --flows path/to/flows --web +# Open http://127.0.0.1:7435 +``` + +Add `--log-level INFO` to either operator launch command to show listener startup, +source-watcher startup and shutdown, changed files, successful catalog revision +transitions, unchanged rescans, and reload failures. The default is `WARNING`; +accepted levels are `DEBUG`, `INFO`, `WARNING`, and `ERROR`. + +The browser shows the live workflow catalog, current definitions, immutable +per-run topology, run controls, logs, and retained agent trace evidence. Source +changes replace only the current-definition canvas; earlier runs keep their +topology and agent input/output field schemas without retaining instruction +bodies or execution configuration. The browser listener is loopback-only by +default. `--web-trusted-proxy` permits a +non-loopback bind only when a trusted, authenticated proxy supplies the missing +security boundary. + + The TUI is a client of the operator; it does not import or execute workflow files itself. To explore the interface without an operator, start mock mode: diff --git a/docs/agent-steps.md b/docs/agent-steps.md index 7f3d279..f995e50 100644 --- a/docs/agent-steps.md +++ b/docs/agent-steps.md @@ -242,6 +242,10 @@ PredictRLM skills. Workflow-scoped defaults configure shared PredictRLM execution policy: +Agent steps are quiet by default (`verbose=False`); set `verbose=True` on an +individual `@ava.agent_step` or in `agent_defaults` when live PredictRLM trace +output is needed. + ```python @ava.workflow( input=PreparedInputs, @@ -264,7 +268,8 @@ async def expensive_audit(..., *, agent: ava.Agent): Resolution order: ```text -agent-step runtime kwargs > workflow agent_defaults > PredictRLM defaults +agent-step runtime kwargs > workflow agent_defaults > Avalanche agent defaults > +PredictRLM defaults ``` Workflow defaults cannot configure `signature`, `skills`, or `tools`; those are diff --git a/docs/getting-started.md b/docs/getting-started.md index 2367bb9..3c389fb 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -124,6 +124,11 @@ To run them separately, start the operator in one terminal: uv run ava operator --flows examples --port 7433 ``` +Operator terminal logging defaults to `WARNING`. Add `--log-level INFO` to see +service and source-watcher startup, each hot-reload attempt, successful revision +transitions, unchanged rescans, reload failures, and watcher shutdown. The flag +also works with the `python -m avalanche.operator` entry point. + Start a discovered flow from another terminal with the CLI: ```bash @@ -136,6 +141,21 @@ Alternatively, connect the TUI and start runs interactively: uv run ava tui --connect localhost:7433 ``` +Or enable the operator's browser interface: + +```bash +uv run ava operator --flows examples --web +``` + +Open `http://127.0.0.1:7435`. The browser receives the same ordered operator +updates as the TUI, including live catalog replacement when watched workflow +sources change. Current definitions update in place; historical run canvases +retain the topology and agent declarations captured for that run. The browser +listener defaults to loopback and has no built-in authentication. Use +`--web-trusted-proxy` with a non-loopback `--web-host` only behind a trusted, +authenticated proxy. + + The TUI gets flows from the operator over gRPC. It does not import files from the examples directory directly. diff --git a/src/ava_cli/app.py b/src/ava_cli/app.py index b6c2940..5191998 100644 --- a/src/ava_cli/app.py +++ b/src/ava_cli/app.py @@ -69,6 +69,28 @@ def _build_parser() -> argparse.ArgumentParser: operator.add_argument( "--webhook-port", type=int, default=7434, help="loopback webhook HTTP port" ) + operator.add_argument("--web", action="store_true", help="serve the local browser UI") + operator.add_argument( + "--web-host", + default="127.0.0.1", + help="browser UI listen host (default: loopback)", + ) + operator.add_argument("--web-port", type=int, default=7435, help="browser UI HTTP port") + operator.add_argument( + "--web-trusted-proxy", + action="store_true", + help=( + "confirm non-loopback browser traffic is protected by an external trusted " + "and authenticated boundary" + ), + ) + operator.add_argument( + "--log-level", + type=str.upper, + choices=("DEBUG", "INFO", "WARNING", "ERROR"), + default="WARNING", + help="terminal log level (default: WARNING)", + ) operator.add_argument("--ray", action="store_true", help="use the Ray executor") operator.set_defaults(handler=_run_operator) @@ -215,7 +237,21 @@ def _run_operator(args: argparse.Namespace) -> int: str(args.port), "--webhook-port", str(args.webhook_port), + "--log-level", + args.log_level, ] + if args.web: + runtime_args.extend( + [ + "--web", + "--web-host", + args.web_host, + "--web-port", + str(args.web_port), + ] + ) + if args.web_trusted_proxy: + runtime_args.append("--web-trusted-proxy") if args.ray: runtime_args.append("--ray") return _operator_main(runtime_args) diff --git a/src/avalanche/agent/agent_step.py b/src/avalanche/agent/agent_step.py index 033eb5b..5ba3116 100644 --- a/src/avalanche/agent/agent_step.py +++ b/src/avalanche/agent/agent_step.py @@ -12,7 +12,9 @@ from enum import Enum from functools import update_wrapper from pathlib import Path -from typing import Any, Callable, Mapping, Sequence, Union, get_args, get_origin +from typing import Any, Callable, Mapping, Sequence, TypeAlias, Union, get_args, get_origin + +from pydantic import BaseModel from .._agent_evidence import AgentInvocationId, emit_agent_evidence from ..dag import Node, NodeType @@ -32,6 +34,8 @@ class AgentStepExecutionError(RuntimeError): "avalanche_agent_workflow_defaults", default={} ) +_AGENT_RUNTIME_DEFAULTS: Mapping[str, bool] = types.MappingProxyType({"verbose": False}) + class _AgentInvocationState: """Task-local evidence state for one agent invocation.""" @@ -92,6 +96,62 @@ def _emit_sink_evidence( raise +JsonValue: TypeAlias = ( + str | int | float | bool | None | list["JsonValue"] | dict[str, "JsonValue"] +) +_MAX_EVIDENCE_VALUE_BYTES = 4 * 1024 * 1024 +_MAX_EVIDENCE_COLLECTION_ITEMS = 10_000 +_MAX_EVIDENCE_DEPTH = 32 + + +def _unavailable_value(reason: str) -> dict[str, JsonValue]: + return {"kind": "unavailable", "reason": reason} + + +def _project_agent_value(value: object, *, depth: int = 0) -> JsonValue: + if depth > _MAX_EVIDENCE_DEPTH: + return _unavailable_value("maximum nesting depth exceeded") + if value is None or isinstance(value, (str, bool, int)): + return value + if isinstance(value, float): + return value if math.isfinite(value) else _unavailable_value("non-finite number") + + try: + import predict_rlm + except ImportError: + predict_rlm = None + if predict_rlm is not None and isinstance(value, predict_rlm.File): + path = value.path + if isinstance(path, str) and path: + return {"kind": "predict_rlm_file", "path": path} + return _unavailable_value("PredictRLM file has no host path") + + if isinstance(value, BaseModel): + value = value.model_dump(mode="python") + if isinstance(value, Mapping): + if len(value) > _MAX_EVIDENCE_COLLECTION_ITEMS: + return _unavailable_value("mapping exceeds item limit") + projected: dict[str, JsonValue] = {} + for key, item in value.items(): + if not isinstance(key, str): + return _unavailable_value("mapping keys must be strings") + projected[key] = _project_agent_value(item, depth=depth + 1) + return projected + if isinstance(value, (list, tuple)): + if len(value) > _MAX_EVIDENCE_COLLECTION_ITEMS: + return _unavailable_value("sequence exceeds item limit") + return [_project_agent_value(item, depth=depth + 1) for item in value] + return _unavailable_value(f"unsupported value type: {type(value).__name__}") + + +def _bounded_agent_value(value: object) -> JsonValue: + projected = _project_agent_value(value) + encoded = json.dumps(projected, separators=(",", ":")).encode() + if len(encoded) > _MAX_EVIDENCE_VALUE_BYTES: + return _unavailable_value("value exceeds byte limit") + return projected + + def _project_evidence_event( event: Any, *, @@ -105,13 +165,16 @@ def _project_evidence_event( if event_kind == "run.started": inputs = data.get("inputs") - projected["input_fields"] = sorted(inputs) if isinstance(inputs, Mapping) else [] + projected_inputs = _bounded_agent_value(inputs) if isinstance(inputs, Mapping) else {} + projected = { + "input_fields": sorted(inputs) if isinstance(inputs, Mapping) else [], + "inputs": projected_inputs, + } elif event_kind == "iteration.recorded": step = data.get("step") step = step if isinstance(step, Mapping) else {} projected = { "iteration": step.get("iteration"), - "reasoning": step.get("reasoning"), "duration_ms": step.get("duration_ms"), "error": step.get("error"), "tool_count": len(step.get("tool_calls") or []), @@ -120,6 +183,7 @@ def _project_evidence_event( for group in (step.get("predict_calls") or []) if isinstance(group, Mapping) ), + "step": _bounded_agent_value(step), } elif event_kind == "predict.started": projected = { @@ -149,7 +213,8 @@ def _project_evidence_event( } elif event_kind == "run.succeeded": projected = { - key: data.get(key) for key in ("status", "outputs") if data.get(key) is not None + "status": data.get("status"), + "outputs": _bounded_agent_value(data.get("outputs", {})), } elif event_kind in {"run.failed", "run.cancelled"}: projected = { @@ -341,11 +406,32 @@ def make_agent(self) -> Agent: return Agent( signature=self.signature, step_name=self.step_name, - runtime_kwargs={**defaults, **self.runtime_kwargs}, + runtime_kwargs={ + **_AGENT_RUNTIME_DEFAULTS, + **defaults, + **self.runtime_kwargs, + }, skills=self.skills, tools=self.tools, ) + def field_schema_metadata(self) -> dict[str, list[dict[str, str]]]: + """Serialize only the declared invocation field schemas.""" + signature = resolve_signature(self.signature, name=self.step_name) + return { + "inputs": _serialize_signature_fields(signature.input_fields, type_key="type"), + "outputs": _serialize_signature_fields(signature.output_fields, type_key="type"), + } + + def signature_instruction_line(self) -> str: + """Return the first non-empty signature instruction line.""" + signature = resolve_signature(self.signature, name=self.step_name) + instructions = str(getattr(signature, "instructions", "") or "") + return next( + (line.strip() for line in instructions.splitlines() if line.strip()), + "", + ) + def declaration_metadata( self, workflow_defaults: Mapping[str, Any] | None = None ) -> dict[str, Any]: @@ -415,7 +501,9 @@ async def bound(*args: Any, **kwargs: Any) -> Any: _SECRET_KEY_PARTS = ("api_key", "auth", "credential", "password", "secret", "token") -def _serialize_signature_fields(fields: Mapping[str, Any]) -> list[dict[str, str]]: +def _serialize_signature_fields( + fields: Mapping[str, Any], *, type_key: str = "annotation" +) -> list[dict[str, str]]: serialized = [] for name, field in fields.items(): extra = getattr(field, "json_schema_extra", None) @@ -425,7 +513,7 @@ def _serialize_signature_fields(fields: Mapping[str, Any]) -> list[dict[str, str serialized.append( { "name": name, - "annotation": _annotation_name(getattr(field, "annotation", Any)), + type_key: _annotation_name(getattr(field, "annotation", Any)), "description": description if isinstance(description, str) else "", } ) @@ -500,6 +588,7 @@ def _effective_runtime_metadata( if name not in {"self", "signature", "skills", "tools"} and parameter.default is not inspect.Parameter.empty } + effective.update(_AGENT_RUNTIME_DEFAULTS) effective.update(workflow_defaults) effective.update(step_overrides) serialized: dict[str, Any] = {} diff --git a/src/runtime/operator/__init__.py b/src/runtime/operator/__init__.py index 1391f46..cbdb74d 100644 --- a/src/runtime/operator/__init__.py +++ b/src/runtime/operator/__init__.py @@ -33,13 +33,29 @@ def serve( *, host: str = "127.0.0.1", webhook_port: int = 7434, + web: bool = False, + web_host: str = "127.0.0.1", + web_port: int = 7435, + web_trusted_proxy: bool = False, **kwargs, ) -> None: - """Start the operator daemon with gRPC server.""" + """Start the operator daemon with gRPC and optional browser listeners.""" from .server import serve as _serve + from .web import start_browser_server op = Operator(workflow_paths, webhook_port=webhook_port, **kwargs) + browser_server = None try: + if web: + browser_server = start_browser_server( + op, + host=web_host, + port=web_port, + trust_non_loopback=web_trusted_proxy, + ) + print(f"Avalanche web UI: {browser_server.endpoint}") _serve(op, port=port, block=True, host=host) finally: + if browser_server is not None: + browser_server.close() op.close() diff --git a/src/runtime/operator/__main__.py b/src/runtime/operator/__main__.py index 712330d..1629741 100644 --- a/src/runtime/operator/__main__.py +++ b/src/runtime/operator/__main__.py @@ -3,6 +3,7 @@ from __future__ import annotations import argparse +import logging from collections.abc import Sequence @@ -31,7 +32,34 @@ def main(argv: Sequence[str] | None = None) -> int: "--webhook-port", type=int, default=7434, help="loopback webhook HTTP port" ) parser.add_argument("--ray", action="store_true", help="use the Ray executor") + parser.add_argument("--web", action="store_true", help="serve the local browser UI") + parser.add_argument( + "--web-host", + default="127.0.0.1", + help="browser UI listen host (default: loopback)", + ) + parser.add_argument("--web-port", type=int, default=7435, help="browser UI HTTP port") + parser.add_argument( + "--web-trusted-proxy", + action="store_true", + help=( + "confirm non-loopback browser traffic is protected by an external trusted " + "and authenticated boundary" + ), + ) + parser.add_argument( + "--log-level", + type=str.upper, + choices=("DEBUG", "INFO", "WARNING", "ERROR"), + default="WARNING", + help="terminal log level (default: WARNING)", + ) args = parser.parse_args(list(argv) if argv is not None else None) + logging.basicConfig( + level=getattr(logging, args.log_level), + format="%(asctime)s %(levelname)s %(name)s: %(message)s", + force=True, + ) if args.ray: print("Executor: Ray") @@ -48,6 +76,10 @@ def main(argv: Sequence[str] | None = None) -> int: host=args.host, webhook_port=args.webhook_port, executor_backend="ray" if args.ray else "local", + web=args.web, + web_host=args.web_host, + web_port=args.web_port, + web_trusted_proxy=args.web_trusted_proxy, ) return 0 diff --git a/src/runtime/operator/client.py b/src/runtime/operator/client.py index 2fc887c..e599930 100644 --- a/src/runtime/operator/client.py +++ b/src/runtime/operator/client.py @@ -22,30 +22,31 @@ from ._grpc import _BOUNDED_MESSAGE_OPTIONS from .convert import ( agent_event_descriptor_from_proto, - discovery_diagnostic_from_proto, + catalog_snapshot_from_proto, log_record_descriptor_from_proto, + operator_update_envelope_from_proto, run_snapshot_from_proto, run_summary_from_proto, - run_update_envelope_from_proto, - workflow_info_from_proto, ) from .models import ( AgentEvent, AgentEventAppended, AgentEventDetailAppended, + CatalogReplaced, + CatalogSnapshot, DetailUpdate, LogAppended, LogDetailAppended, LogEntry, NodeState, NodeStatusChanged, + OperatorUpdateEnvelope, ResetBaseline, RunCreated, RunSnapshot, RunState, RunStatusChanged, RunSummary, - RunUpdateEnvelope, SequencedLogEntry, StreamResetNotice, TraceDetail, @@ -243,6 +244,7 @@ def __init__( ) self._stub = pb_grpc.OperatorServiceStub(self._channel) self._run_callbacks: list[Callable[[RunState], None]] = [] + self._catalog_callbacks: list[Callable[[CatalogSnapshot], None]] = [] self._log_callbacks: list[Callable[[LogEntry], None]] = [] self._detail_callbacks: list[Callable[[DetailUpdate], None]] = [] self._stream_reset_callbacks: list[Callable[[StreamResetNotice], None]] = [] @@ -272,7 +274,7 @@ def __init__( self._reset_generation: int = 0 self._pending_reset: StreamResetNotice | None = None self._validated_reset_baseline: ResetBaseline | None = None - self._legacy_names_by_workflow_id: dict[str, str] = {} + self._catalog = CatalogSnapshot() # Operator reachability is independent from live-update stream health. self.operator_instance_id: str = "" @@ -339,13 +341,14 @@ def _record_unary_error(self, error: grpc.RpcError) -> OperatorCallError: self.last_error = str(operation_error) return operation_error + def get_catalog(self) -> CatalogSnapshot: + catalog = catalog_snapshot_from_proto(self._call(self._stub.GetCatalog, pb.Empty())) + with self._state_lock: + self._install_catalog_locked(catalog) + return catalog + def list_workflows(self) -> list[WorkflowInfo]: - resp = self._call(self._stub.ListFlows, pb.Empty()) - self._cache_legacy_workflow_names(resp) - self.discovery_diagnostics = [ - discovery_diagnostic_from_proto(item) for item in resp.diagnostics - ] - return [workflow_info_from_proto(p) for p in resp.flows] + return list(self.get_catalog().workflows) def list_runs(self, workflow_selector: str) -> list[RunState]: """List lightweight run summaries without detail bodies.""" @@ -396,6 +399,21 @@ def _validate_page_accumulation(self, count: int, item_name: str) -> None: f"client {item_name} exceed the configured pagination item limit", ) + def get_latest_run_snapshot( + self, + run_id: str, + operator_instance_id: str, + ) -> RunSnapshot: + """Fetch one latest structural snapshot pinned to an operator epoch.""" + response = self._call( + self._stub.GetLatestRunSnapshot, + pb.GetLatestRunSnapshotRequest( + run_id=run_id, + operator_instance_id=operator_instance_id, + ), + ) + return run_snapshot_from_proto(response) + def get_run(self, run_id: str) -> RunState | None: """Fetch one pinned structural snapshot and lazily hydrate its details.""" last_race: _DetailHydrationRaceError | None = None @@ -664,6 +682,9 @@ def _read_log_pages( page_token=token, after_sequence=cursor, page_size=DETAIL_HYDRATION_PAGE_SIZE, + before_sequence=0, + node_id="", + order=pb.DESCRIPTOR_PAGE_ORDER_FORWARD, ), ) self._validate_detail_page( @@ -722,6 +743,8 @@ def _read_agent_event_pages( page_token=token, after_event_sequence=cursor, page_size=DETAIL_HYDRATION_PAGE_SIZE, + before_event_sequence=0, + order=pb.DESCRIPTOR_PAGE_ORDER_FORWARD, ), ) self._validate_detail_page( @@ -747,6 +770,12 @@ def _read_agent_event_pages( event_sequence=descriptor.event_sequence, event_json=event_json, size_bytes=descriptor.size_bytes, + event_kind=descriptor.event_kind, + iteration=descriptor.iteration, + duration_ms=descriptor.duration_ms, + error=descriptor.error, + tool_count=descriptor.tool_count, + predict_count=descriptor.predict_count, ) ) cursor = descriptor.event_sequence @@ -1207,9 +1236,7 @@ def start_run( input_files = [ _file_attachment(field_name, value) for field_name, value in (files or {}).items() ] - flow_name = self._legacy_names_by_workflow_id.get(workflow_selector, workflow_selector) request = pb.StartRunRequest( - flow_name=flow_name, workflow_selector=workflow_selector, run_id=run_id or "", input_json=_json_payload(input), @@ -1225,6 +1252,9 @@ def cancel_run(self, run_id: str) -> None: def on_run_update(self, callback: Callable[[RunState], None]) -> None: self._run_callbacks.append(callback) + def on_catalog_update(self, callback: Callable[[CatalogSnapshot], None]) -> None: + self._catalog_callbacks.append(callback) + def on_log(self, callback: Callable[[LogEntry], None]) -> None: self._log_callbacks.append(callback) @@ -1272,22 +1302,32 @@ def load_reset_baseline(self, notice: StreamResetNotice) -> ResetBaseline: ) from last_error def _load_authoritative_reset_baseline(self, notice: StreamResetNotice) -> ResetBaseline: - workflows = tuple(self.list_workflows()) + catalog = self.get_catalog() marker, summaries = self._list_run_summaries() snapshots = [ self._get_consistent_run_snapshot(summary, marker) for summary in summaries ] - if tuple(self.list_workflows()) != workflows: + confirmed_catalog = self.get_catalog() + if replace(confirmed_catalog, as_of_sequence=0) != replace(catalog, as_of_sequence=0): raise _ResetBaselineMismatchError( "workflow catalog changed during baseline loading" ) + if ( + catalog.operator_instance_id != marker[0] + or confirmed_catalog.operator_instance_id != marker[0] + or catalog.as_of_sequence > marker[1] + or confirmed_catalog.as_of_sequence < marker[1] + ): + raise _ResetBaselineMismatchError( + "workflow catalog does not span the run baseline high-water mark" + ) - runs_by_workflow = self._group_snapshot_runs(workflows, snapshots) + runs_by_workflow = self._group_snapshot_runs(catalog.workflows, snapshots) return ResetBaseline( generation=notice.generation, operator_instance_id=marker[0], as_of_sequence=marker[1], - workflows=workflows, + catalog=catalog, runs_by_workflow=runs_by_workflow, ) @@ -1494,6 +1534,8 @@ def acknowledge_stream_reset( for workflow_runs in validated.runs_by_workflow.values() for run in workflow_runs } + with self._state_lock: + self._install_catalog_locked(validated.catalog) self._replace_structural_baseline( operator_instance_id, reconciled_sequence, @@ -1505,6 +1547,7 @@ def acknowledge_stream_reset( self.stream_retry_count = 0 self.stream_error = "" self._reset_acknowledged.set() + self._notify_catalog_callbacks(validated.catalog) def _ensure_stream(self) -> None: """Start the background streaming thread if not already running.""" @@ -1524,22 +1567,25 @@ def ping(self) -> bool: kwargs = {"timeout": min(2.0, self._unary_timeout)} if self._metadata is not None: kwargs["metadata"] = self._metadata - resp = self._stub.ListFlows(pb.Empty(), **kwargs) - self._cache_legacy_workflow_names(resp) + self._stub.GetCatalog(pb.Empty(), **kwargs) self._record_unary_success() return True except grpc.RpcError as e: self._record_unary_error(e) return False - def _cache_legacy_workflow_names(self, response: pb.FlowList) -> None: - self._legacy_names_by_workflow_id = { - (item.workflow_id or item.name): (item.name or item.display_name) - for item in response.flows - } + + def _install_catalog_locked(self, catalog: CatalogSnapshot) -> None: + if ( + catalog.operator_instance_id == self._catalog.operator_instance_id + and catalog.revision < self._catalog.revision + ): + return + self._catalog = deepcopy(catalog) + self.discovery_diagnostics = list(catalog.diagnostics) def _stream_loop(self) -> None: - """Consume ordered run updates without conflating stream and unary health.""" + """Consume ordered operator updates without conflating stream and unary health.""" while not self._stream_stop.is_set(): try: with self._lifecycle_lock: @@ -1550,8 +1596,8 @@ def _stream_loop(self) -> None: self.stream_retry_count += 1 with self._state_lock: cursor = self._cursor - stream = self._stub.StreamRunUpdates( - pb.StreamRunUpdatesRequest( + stream = self._stub.StreamOperatorUpdates( + pb.StreamOperatorUpdatesRequest( operator_instance_id=cursor.operator_instance_id, after_sequence=cursor.sequence, ), @@ -1578,7 +1624,7 @@ def _stream_loop(self) -> None: for message in stream: if self._stream_stop.is_set(): break - envelope = run_update_envelope_from_proto(message) + envelope = operator_update_envelope_from_proto(message) if not envelope.operator_instance_id: raise RuntimeError( "update envelope omitted its operator instance identifier" @@ -1636,7 +1682,7 @@ def _stream_loop(self) -> None: continue if self._stream_stop.is_set(): break - raise RuntimeError("update stream ended") + raise RuntimeError("operator update stream ended") except grpc.RpcError as error: if self._stream_stop.is_set(): break @@ -1688,7 +1734,7 @@ def _require_stream_reset( break def _apply_update_envelope( - self, envelope: RunUpdateEnvelope + self, envelope: OperatorUpdateEnvelope ) -> tuple[RunState | None, DetailUpdate | None]: update = envelope.update with self._state_lock: @@ -1717,18 +1763,32 @@ def _apply_update_envelope( descriptor.body_token, descriptor.size_bytes, ).decode(), + event_kind=descriptor.event_kind, + iteration=descriptor.iteration, + duration_ms=descriptor.duration_ms, + error=descriptor.error, + tool_count=descriptor.tool_count, + predict_count=descriptor.predict_count, size_bytes=descriptor.size_bytes, ) with self._state_lock: - return self._apply_update_envelope_locked( + result = self._apply_update_envelope_locked( envelope, log_detail=log_detail, event_detail=event_detail, ) + catalog = ( + deepcopy(self._catalog) + if update is not None and isinstance(update.change, CatalogReplaced) + else None + ) + if catalog is not None: + self._notify_catalog_callbacks(catalog) + return result def _apply_update_envelope_locked( self, - envelope: RunUpdateEnvelope, + envelope: OperatorUpdateEnvelope, *, log_detail: LogEntry | None = None, event_detail: AgentEvent | None = None, @@ -1753,7 +1813,16 @@ def _apply_update_envelope_locked( change = update.change detail: DetailUpdate | None = None - if isinstance(change, RunCreated): + if isinstance(change, CatalogReplaced): + catalog = change.catalog + if ( + catalog.operator_instance_id != envelope.operator_instance_id + or catalog.as_of_sequence != update.sequence + ): + raise _RunUpdateResetError("catalog update marker mismatch") + self._install_catalog_locked(catalog) + run = None + elif isinstance(change, RunCreated): run = _run_from_created(envelope.operator_instance_id, change) old_revision = self._run_revisions.get(run.run_id, -1) if change.summary.revision <= old_revision: @@ -1797,6 +1866,7 @@ def _apply_update_envelope_locked( node.status = change.status node.started_at = change.started_at node.ended_at = change.ended_at + node.error = change.error node.revision = change.revision run.nodes = dict(current.nodes) run.nodes[change.node_id] = node @@ -1970,6 +2040,13 @@ def _replace_structural_baseline( self.operator_instance_id = operator_instance_id self._cursor = _StreamCursor(operator_instance_id, as_of_sequence) + def _notify_catalog_callbacks(self, catalog: CatalogSnapshot) -> None: + for callback in self._catalog_callbacks: + try: + callback(deepcopy(catalog)) + except Exception: + pass + def _notify_run_callbacks(self, run: RunState) -> None: for callback in self._run_callbacks: try: @@ -2049,10 +2126,12 @@ def _run_from_created(operator_instance_id: str, created: RunCreated) -> RunStat flow_name=summary.flow_name, status=summary.status, started_at=summary.started_at, + triggered_at=summary.triggered_at, ended_at=summary.ended_at, triggered_by=summary.triggered_by, workflow_id=summary.workflow_id, workflow_display_name=summary.workflow_display_name, + topology=created.topology, operator_instance_id=operator_instance_id, created_sequence=summary.created_sequence, revision=summary.revision, @@ -2066,6 +2145,7 @@ def _run_from_created(operator_instance_id: str, created: RunCreated) -> RunStat status=item.status, started_at=item.started_at, ended_at=item.ended_at, + error=item.error, trace=item.trace, revision=item.revision, event_page_token=item.event_page_token, @@ -2079,7 +2159,11 @@ def _run_from_snapshot(snapshot: RunSnapshot) -> RunState: """Materialize the authoritative structural baseline used by the reducer.""" run = _run_from_created( snapshot.operator_instance_id, - RunCreated(summary=snapshot.summary, nodes=snapshot.nodes), + RunCreated( + summary=snapshot.summary, + nodes=snapshot.nodes, + topology=snapshot.topology, + ), ) run.latest_log_sequence = snapshot.latest_log_sequence run.details_hydrated = False @@ -2124,17 +2208,43 @@ def _materialize_agent_trace_json( status: str, trace_body: dict[str, Any] | None, ) -> str: + reconstructed = deepcopy(trace_body) if trace_body is not None else None + if reconstructed is not None: + steps = [] + evidence_events = [] + for event in events: + if not isinstance(event, dict): + continue + event_kind = event.get("event_kind") + data = event.get("data") + if event_kind == "iteration.recorded" and isinstance(data, dict): + step = data.get("step") + if isinstance(step, dict): + steps.append(step) + evidence_events.append( + { + "sequence": event.get("sequence"), + "kind": event_kind, + "timestamp_ns": event.get("timestamp_ns"), + "data": data if isinstance(data, dict) else {}, + } + ) + reconstructed["steps"] = steps + evidence = reconstructed.get("evidence") + if isinstance(evidence, dict): + evidence["events"] = evidence_events + envelope: dict[str, Any] = { "schema_version": 1, "status": status, "run_id": None, "events": events, - "trace": trace_body, + "trace": reconstructed, "error": None, } - if trace_body is not None: - envelope["status"] = str(trace_body.get("status") or status) - evidence = trace_body.get("evidence") + if reconstructed is not None: + envelope["status"] = str(reconstructed.get("status") or status) + evidence = reconstructed.get("evidence") if isinstance(evidence, dict): envelope["run_id"] = evidence.get("run_id") return json.dumps(envelope, default=str) diff --git a/src/runtime/operator/convert.py b/src/runtime/operator/convert.py index 66b2e0b..6ddf2b6 100644 --- a/src/runtime/operator/convert.py +++ b/src/runtime/operator/convert.py @@ -7,24 +7,29 @@ from .models import ( AgentEventAppended, AgentEventDescriptor, + CatalogReplaced, + CatalogSnapshot, LogAppended, LogLevel, LogRecordDescriptor, NodeSnapshot, NodeStatus, NodeStatusChanged, + OperatorUpdate, + OperatorUpdateEnvelope, ResetRequired, RunCreated, RunSnapshot, RunStatus, RunStatusChanged, RunSummary, - RunUpdate, - RunUpdateEnvelope, + ScanTargetInfo, TraceDescriptor, TraceFinalized, + TraceHeader, WorkflowDiscoveryDiagnostic, WorkflowInfo, + WorkflowTopology, ) from .proto import operator_pb2 as pb @@ -105,8 +110,108 @@ def discovery_diagnostic_from_proto( ) +def scan_target_to_proto(target: ScanTargetInfo) -> pb.ScanTargetMsg: + return pb.ScanTargetMsg( + alias=target.alias, + target_path=target.target_path, + kind=target.kind, + ) + + +def scan_target_from_proto(msg: pb.ScanTargetMsg) -> ScanTargetInfo: + if msg.kind not in {"file", "directory"}: + raise ValueError(f"Unknown scan target kind: {msg.kind}") + return ScanTargetInfo( + alias=msg.alias, + target_path=msg.target_path, + kind=msg.kind, + ) + + +def catalog_snapshot_to_proto(catalog: CatalogSnapshot) -> pb.CatalogSnapshotMsg: + return pb.CatalogSnapshotMsg( + revision=catalog.revision, + operator_instance_id=catalog.operator_instance_id, + as_of_sequence=catalog.as_of_sequence, + workflows=[workflow_info_to_proto(item) for item in catalog.workflows], + scan_targets=[scan_target_to_proto(item) for item in catalog.scan_targets], + diagnostics=[discovery_diagnostic_to_proto(item) for item in catalog.diagnostics], + ) + + +def catalog_snapshot_from_proto(msg: pb.CatalogSnapshotMsg) -> CatalogSnapshot: + return CatalogSnapshot( + revision=msg.revision, + workflows=tuple(workflow_info_from_proto(item) for item in msg.workflows), + operator_instance_id=msg.operator_instance_id, + as_of_sequence=msg.as_of_sequence, + scan_targets=tuple(scan_target_from_proto(item) for item in msg.scan_targets), + diagnostics=tuple(discovery_diagnostic_from_proto(item) for item in msg.diagnostics), + ) + + +def workflow_topology_to_proto(topology: WorkflowTopology) -> pb.WorkflowTopologyMsg: + return pb.WorkflowTopologyMsg( + node_ids=topology.node_ids, + graph={parent: pb.NodeEdges(children=children) for parent, children in topology.graph}, + node_types=dict(topology.node_types), + display_names=dict(topology.display_names), + agent_field_schemas_json=dict(topology.agent_field_schemas_json), + agent_instruction_lines=dict(topology.agent_instruction_lines), + ) + + +def workflow_topology_from_proto(msg: pb.WorkflowTopologyMsg) -> WorkflowTopology: + node_ids = tuple(msg.node_ids) + return WorkflowTopology( + node_ids=node_ids, + graph=tuple((node_id, tuple(msg.graph[node_id].children)) for node_id in node_ids), + node_types=tuple((node_id, msg.node_types[node_id]) for node_id in node_ids), + display_names=tuple((node_id, msg.display_names[node_id]) for node_id in node_ids), + agent_field_schemas_json=tuple( + (node_id, msg.agent_field_schemas_json[node_id]) + for node_id in node_ids + if node_id in msg.agent_field_schemas_json + ), + agent_instruction_lines=tuple( + (node_id, msg.agent_instruction_lines[node_id]) + for node_id in node_ids + if node_id in msg.agent_instruction_lines + ), + ) + + +def trace_header_to_proto(header: TraceHeader) -> pb.TraceHeaderMsg: + message = pb.TraceHeaderMsg( + status=header.status, + model=header.model, + iterations=header.iterations, + max_iterations=header.max_iterations, + duration_ms=header.duration_ms, + usage_json=header.usage_json, + ) + if header.sub_model is not None: + message.sub_model = header.sub_model + if header.telemetry_json is not None: + message.telemetry_json = header.telemetry_json + return message + + +def trace_header_from_proto(msg: pb.TraceHeaderMsg) -> TraceHeader: + return TraceHeader( + status=msg.status, + model=msg.model, + sub_model=msg.sub_model if msg.HasField("sub_model") else None, + iterations=msg.iterations, + max_iterations=msg.max_iterations, + duration_ms=msg.duration_ms, + usage_json=msg.usage_json, + telemetry_json=msg.telemetry_json if msg.HasField("telemetry_json") else None, + ) + + def trace_descriptor_to_proto(descriptor: TraceDescriptor) -> pb.TraceDescriptorMsg: - return pb.TraceDescriptorMsg( + message = pb.TraceDescriptorMsg( status=descriptor.status, revision=descriptor.revision, available=descriptor.available, @@ -115,6 +220,9 @@ def trace_descriptor_to_proto(descriptor: TraceDescriptor) -> pb.TraceDescriptor size_bytes=descriptor.size_bytes, latest_event_sequence=descriptor.latest_event_sequence, ) + if descriptor.header is not None: + message.header.CopyFrom(trace_header_to_proto(descriptor.header)) + return message def trace_descriptor_from_proto(msg: pb.TraceDescriptorMsg) -> TraceDescriptor: @@ -126,6 +234,7 @@ def trace_descriptor_from_proto(msg: pb.TraceDescriptorMsg) -> TraceDescriptor: event_count=msg.event_count, size_bytes=msg.size_bytes, latest_event_sequence=msg.latest_event_sequence, + header=trace_header_from_proto(msg.header) if msg.HasField("header") else None, ) @@ -139,9 +248,13 @@ def node_snapshot_to_proto(node: NodeSnapshot) -> pb.NodeSnapshotMsg: ended_at=node.ended_at or 0.0, revision=node.revision, ) + if node.running_elapsed_seconds is not None: + message.running_elapsed_seconds = node.running_elapsed_seconds if node.trace is not None: message.trace.CopyFrom(trace_descriptor_to_proto(node.trace)) message.event_page_token = node.event_page_token + if node.error is not None: + message.error = node.error return message @@ -153,6 +266,10 @@ def node_snapshot_from_proto(msg: pb.NodeSnapshotMsg) -> NodeSnapshot: status=NodeStatus(msg.status), started_at=msg.started_at if msg.started_at else None, ended_at=msg.ended_at if msg.ended_at else None, + running_elapsed_seconds=( + msg.running_elapsed_seconds if msg.HasField("running_elapsed_seconds") else None + ), + error=msg.error if msg.HasField("error") else None, trace=trace_descriptor_from_proto(msg.trace) if msg.HasField("trace") else None, revision=msg.revision, event_page_token=msg.event_page_token, @@ -164,6 +281,7 @@ def run_summary_to_proto(summary: RunSummary) -> pb.RunSummaryMsg: run_id=summary.run_id, flow_name=summary.flow_name, status=summary.status.value, + triggered_at=summary.triggered_at or 0.0, started_at=summary.started_at or 0.0, ended_at=summary.ended_at or 0.0, triggered_by=summary.triggered_by, @@ -180,6 +298,7 @@ def run_summary_from_proto(msg: pb.RunSummaryMsg) -> RunSummary: flow_name=msg.flow_name, status=RunStatus(msg.status), started_at=msg.started_at if msg.started_at else None, + triggered_at=msg.triggered_at if msg.triggered_at else None, ended_at=msg.ended_at if msg.ended_at else None, triggered_by=msg.triggered_by or "manual", workflow_id=msg.workflow_id or msg.flow_name, @@ -197,6 +316,7 @@ def run_snapshot_to_proto(snapshot: RunSnapshot) -> pb.RunSnapshotMsg: nodes=[node_snapshot_to_proto(node) for node in snapshot.nodes], latest_log_sequence=snapshot.latest_log_sequence, log_page_token=snapshot.log_page_token, + topology=workflow_topology_to_proto(snapshot.topology), ) @@ -208,6 +328,7 @@ def run_snapshot_from_proto(msg: pb.RunSnapshotMsg) -> RunSnapshot: nodes=tuple(node_snapshot_from_proto(node) for node in msg.nodes), latest_log_sequence=msg.latest_log_sequence, log_page_token=msg.log_page_token, + topology=workflow_topology_from_proto(msg.topology), ) @@ -242,12 +363,21 @@ def log_record_descriptor_from_proto( def agent_event_descriptor_to_proto( event: AgentEventDescriptor, ) -> pb.AgentEventDescriptorMsg: - return pb.AgentEventDescriptorMsg( + message = pb.AgentEventDescriptorMsg( invocation_id=event.invocation_id, event_sequence=event.event_sequence, size_bytes=event.size_bytes, body_token=event.body_token, + event_kind=event.event_kind, + error=event.error, + tool_count=event.tool_count, + predict_count=event.predict_count, ) + if event.iteration is not None: + message.iteration = event.iteration + if event.duration_ms is not None: + message.duration_ms = event.duration_ms + return message def agent_event_descriptor_from_proto( @@ -258,17 +388,24 @@ def agent_event_descriptor_from_proto( event_sequence=msg.event_sequence, size_bytes=msg.size_bytes, body_token=msg.body_token, + event_kind=msg.event_kind, + iteration=msg.iteration if msg.HasField("iteration") else None, + duration_ms=msg.duration_ms if msg.HasField("duration_ms") else None, + error=msg.error, + tool_count=msg.tool_count, + predict_count=msg.predict_count, ) -def run_update_to_proto(update: RunUpdate) -> pb.RunUpdate: - message = pb.RunUpdate(sequence=update.sequence) +def operator_update_to_proto(update: OperatorUpdate) -> pb.OperatorUpdate: + message = pb.OperatorUpdate(sequence=update.sequence) change = update.change if isinstance(change, RunCreated): message.run_created.CopyFrom( pb.RunCreated( summary=run_summary_to_proto(change.summary), nodes=[node_snapshot_to_proto(node) for node in change.nodes], + topology=workflow_topology_to_proto(change.topology), ) ) elif isinstance(change, RunStatusChanged): @@ -282,16 +419,19 @@ def run_update_to_proto(update: RunUpdate) -> pb.RunUpdate: ) ) elif isinstance(change, NodeStatusChanged): - message.node_status_changed.CopyFrom( - pb.NodeStatusChanged( - run_id=change.run_id, - node_id=change.node_id, - status=change.status.value, - started_at=change.started_at or 0.0, - ended_at=change.ended_at or 0.0, - revision=change.revision, - ) + changed = pb.NodeStatusChanged( + run_id=change.run_id, + node_id=change.node_id, + status=change.status.value, + started_at=change.started_at or 0.0, + ended_at=change.ended_at or 0.0, + revision=change.revision, ) + if change.running_elapsed_seconds is not None: + changed.running_elapsed_seconds = change.running_elapsed_seconds + if change.error is not None: + changed.error = change.error + message.node_status_changed.CopyFrom(changed) elif isinstance(change, LogAppended): message.log_appended.CopyFrom( pb.LogAppended( @@ -315,17 +455,22 @@ def run_update_to_proto(update: RunUpdate) -> pb.RunUpdate: trace=trace_descriptor_to_proto(change.trace), ) ) + elif isinstance(change, CatalogReplaced): + message.catalog_replaced.CopyFrom( + pb.CatalogReplaced(catalog=catalog_snapshot_to_proto(change.catalog)) + ) else: - raise TypeError(f"Unsupported run update change: {type(change).__name__}") + raise TypeError(f"Unsupported operator update change: {type(change).__name__}") return message -def run_update_from_proto(msg: pb.RunUpdate) -> RunUpdate: +def operator_update_from_proto(msg: pb.OperatorUpdate) -> OperatorUpdate: change_name = msg.WhichOneof("change") if change_name == "run_created": change = RunCreated( summary=run_summary_from_proto(msg.run_created.summary), nodes=tuple(node_snapshot_from_proto(node) for node in msg.run_created.nodes), + topology=workflow_topology_from_proto(msg.run_created.topology), ) elif change_name == "run_status_changed": item = msg.run_status_changed @@ -344,6 +489,12 @@ def run_update_from_proto(msg: pb.RunUpdate) -> RunUpdate: status=NodeStatus(item.status), started_at=item.started_at if item.started_at else None, ended_at=item.ended_at if item.ended_at else None, + error=item.error if item.HasField("error") else None, + running_elapsed_seconds=( + item.running_elapsed_seconds + if item.HasField("running_elapsed_seconds") + else None + ), revision=item.revision, ) elif change_name == "log_appended": @@ -366,15 +517,21 @@ def run_update_from_proto(msg: pb.RunUpdate) -> RunUpdate: node_id=item.node_id, trace=trace_descriptor_from_proto(item.trace), ) + elif change_name == "catalog_replaced": + change = CatalogReplaced( + catalog=catalog_snapshot_from_proto(msg.catalog_replaced.catalog) + ) else: - raise ValueError("run update is missing a change") - return RunUpdate(sequence=msg.sequence, change=change) + raise ValueError("operator update is missing a change") + return OperatorUpdate(sequence=msg.sequence, change=change) -def run_update_envelope_to_proto(envelope: RunUpdateEnvelope) -> pb.RunUpdateEnvelope: - message = pb.RunUpdateEnvelope(operator_instance_id=envelope.operator_instance_id) +def operator_update_envelope_to_proto( + envelope: OperatorUpdateEnvelope, +) -> pb.OperatorUpdateEnvelope: + message = pb.OperatorUpdateEnvelope(operator_instance_id=envelope.operator_instance_id) if envelope.update is not None: - message.update.CopyFrom(run_update_to_proto(envelope.update)) + message.update.CopyFrom(operator_update_to_proto(envelope.update)) elif envelope.reset_required is not None: message.reset_required.CopyFrom( pb.ResetRequired( @@ -385,22 +542,24 @@ def run_update_envelope_to_proto(envelope: RunUpdateEnvelope) -> pb.RunUpdateEnv return message -def run_update_envelope_from_proto(msg: pb.RunUpdateEnvelope) -> RunUpdateEnvelope: +def operator_update_envelope_from_proto( + msg: pb.OperatorUpdateEnvelope, +) -> OperatorUpdateEnvelope: payload = msg.WhichOneof("payload") if payload == "update": - return RunUpdateEnvelope( + return OperatorUpdateEnvelope( operator_instance_id=msg.operator_instance_id, - update=run_update_from_proto(msg.update), + update=operator_update_from_proto(msg.update), ) if payload == "reset_required": - return RunUpdateEnvelope( + return OperatorUpdateEnvelope( operator_instance_id=msg.operator_instance_id, reset_required=ResetRequired( history_floor=msg.reset_required.history_floor, latest_sequence=msg.reset_required.latest_sequence, ), ) - raise ValueError("run update envelope is missing a payload") + raise ValueError("operator update envelope is missing a payload") def _relative_source_file(info: WorkflowInfo) -> str: diff --git a/src/runtime/operator/models.py b/src/runtime/operator/models.py index 7eae2c1..840bea1 100644 --- a/src/runtime/operator/models.py +++ b/src/runtime/operator/models.py @@ -19,6 +19,7 @@ class NodeStatus(Enum): class RunStatus(Enum): + REQUESTING = "requesting" PENDING = "pending" RUNNING = "running" SUCCESS = "success" @@ -41,6 +42,18 @@ class LogEntry: message: str +@dataclass(frozen=True) +class WorkflowTopology: + """Immutable rendering metadata captured from one prepared workflow.""" + + node_ids: tuple[str, ...] = () + graph: tuple[tuple[str, tuple[str, ...]], ...] = () + node_types: tuple[tuple[str, str], ...] = () + display_names: tuple[tuple[str, str], ...] = () + agent_field_schemas_json: tuple[tuple[str, str], ...] = () + agent_instruction_lines: tuple[tuple[str, str], ...] = () + + @dataclass class NodeState: node_id: str @@ -49,6 +62,7 @@ class NodeState: status: NodeStatus = NodeStatus.PENDING started_at: float | None = None ended_at: float | None = None + error: str | None = None agent_trace_json: str | None = None trace: TraceDescriptor | None = None revision: int = 0 @@ -67,6 +81,7 @@ class RunState: run_id: str flow_name: str status: RunStatus = RunStatus.PENDING + triggered_at: float | None = None started_at: float | None = None ended_at: float | None = None nodes: dict[str, NodeState] = field(default_factory=dict) @@ -74,6 +89,7 @@ class RunState: triggered_by: str = "manual" # "manual" | "scheduled" workflow_id: str = "" workflow_display_name: str = "" + topology: WorkflowTopology = field(default_factory=WorkflowTopology) operator_instance_id: str = "" created_sequence: int = 0 revision: int = 0 @@ -88,6 +104,20 @@ def elapsed(self) -> float | None: return end - self.started_at +@dataclass(frozen=True) +class TraceHeader: + """RunTrace metadata retained separately from iteration and evidence bodies.""" + + status: str + model: str + sub_model: str | None + iterations: int + max_iterations: int + duration_ms: int + usage_json: str + telemetry_json: str | None = None + + @dataclass(frozen=True) class TraceDescriptor: """Location metadata for agent detail stored outside structural run state.""" @@ -99,6 +129,7 @@ class TraceDescriptor: event_count: int = 0 size_bytes: int = 0 latest_event_sequence: int = 0 + header: TraceHeader | None = None @dataclass(frozen=True) @@ -123,9 +154,11 @@ class NodeSnapshot: status: NodeStatus = NodeStatus.PENDING started_at: float | None = None ended_at: float | None = None + error: str | None = None trace: TraceDescriptor | None = None revision: int = 0 event_page_token: str = "" + running_elapsed_seconds: float | None = None @dataclass(frozen=True) @@ -135,6 +168,7 @@ class RunSummary: run_id: str flow_name: str status: RunStatus = RunStatus.PENDING + triggered_at: float | None = None started_at: float | None = None ended_at: float | None = None triggered_by: str = "manual" @@ -154,6 +188,7 @@ class RunSnapshot: nodes: tuple[NodeSnapshot, ...] = () latest_log_sequence: int = 0 log_page_token: str = "" + topology: WorkflowTopology = field(default_factory=WorkflowTopology) @dataclass(frozen=True) @@ -173,6 +208,12 @@ class AgentEvent: event_sequence: int event_json: str size_bytes: int = 0 + event_kind: str = "" + iteration: int | None = None + duration_ms: int | None = None + error: bool = False + tool_count: int = 0 + predict_count: int = 0 @dataclass(frozen=True) @@ -216,12 +257,18 @@ class LogRecordDescriptor: @dataclass(frozen=True) class AgentEventDescriptor: - """Bounded identity and availability metadata for an agent event body.""" + """Bounded identity, summary, and availability metadata for an agent event body.""" invocation_id: str event_sequence: int size_bytes: int body_token: str + event_kind: str = "" + iteration: int | None = None + duration_ms: int | None = None + error: bool = False + tool_count: int = 0 + predict_count: int = 0 @dataclass(frozen=True) @@ -264,10 +311,39 @@ class FinalizedTrace: data: bytes +@dataclass(frozen=True) +class ScanTargetInfo: + """One normalized workflow discovery target exposed to clients.""" + + alias: str + target_path: str + kind: Literal["file", "directory"] + + +@dataclass(frozen=True) +class CatalogSnapshot: + """One complete authoritative current-workflow catalog projection.""" + + operator_instance_id: str = "" + as_of_sequence: int = 0 + revision: int = 0 + workflows: tuple[WorkflowInfo, ...] = () + scan_targets: tuple[ScanTargetInfo, ...] = () + diagnostics: tuple[WorkflowDiscoveryDiagnostic, ...] = () + + +@dataclass(frozen=True) +class CatalogReplaced: + """One full catalog publication carried by the operator update stream.""" + + catalog: CatalogSnapshot + + @dataclass(frozen=True) class RunCreated: summary: RunSummary nodes: tuple[NodeSnapshot, ...] = () + topology: WorkflowTopology = field(default_factory=WorkflowTopology) @dataclass(frozen=True) @@ -286,7 +362,9 @@ class NodeStatusChanged: status: NodeStatus started_at: float | None = None ended_at: float | None = None + error: str | None = None revision: int = 0 + running_elapsed_seconds: float | None = None @dataclass(frozen=True) @@ -317,12 +395,13 @@ class TraceFinalized: | AgentEventAppended | TraceFinalized ) +OperatorUpdateChange = RunUpdateChange | CatalogReplaced @dataclass(frozen=True) -class RunUpdate: +class OperatorUpdate: sequence: int - change: RunUpdateChange + change: OperatorUpdateChange @dataclass(frozen=True) @@ -332,14 +411,14 @@ class ResetRequired: @dataclass(frozen=True) -class RunUpdateEnvelope: +class OperatorUpdateEnvelope: operator_instance_id: str - update: RunUpdate | None = None + update: OperatorUpdate | None = None reset_required: ResetRequired | None = None def __post_init__(self) -> None: if (self.update is None) == (self.reset_required is None): - raise ValueError("update envelope requires exactly one payload") + raise ValueError("operator update envelope requires exactly one payload") @dataclass @@ -400,14 +479,16 @@ class ResetBaseline: generation: int operator_instance_id: str as_of_sequence: int - workflows: tuple[WorkflowInfo, ...] + catalog: CatalogSnapshot runs_by_workflow: Mapping[str, tuple[RunState, ...]] @dataclass(frozen=True) class WorkflowDiscoveryDiagnostic: path: str - kind: Literal["skipped", "import_error", "build_error", "invalid_schedule"] + kind: Literal[ + "skipped", "import_error", "build_error", "invalid_schedule", "invalid_catalog" + ] message: str @@ -440,14 +521,16 @@ class WorkflowDescriptor: @dataclass(frozen=True) class CatalogView: - """One atomically replaceable, current-only registry view.""" + """One atomically replaceable current-workflow registry view.""" + revision: int = 0 by_id: Mapping[str, WorkflowDescriptor] = field( default_factory=lambda: MappingProxyType({}) ) short_names: Mapping[str, tuple[str, ...]] = field( default_factory=lambda: MappingProxyType({}) ) + scan_targets: tuple[ScanTargetInfo, ...] = () diagnostics: tuple[WorkflowDiscoveryDiagnostic, ...] = () diff --git a/src/runtime/operator/operator.py b/src/runtime/operator/operator.py index 04eaf6c..9a06328 100644 --- a/src/runtime/operator/operator.py +++ b/src/runtime/operator/operator.py @@ -32,6 +32,9 @@ AgentEventDescriptor, AgentEventDetailAppended, AgentEventPage, + CatalogReplaced, + CatalogSnapshot, + CatalogView, DetailUpdate, FinalizedTrace, LogAppended, @@ -44,6 +47,8 @@ NodeState, NodeStatus, NodeStatusChanged, + OperatorUpdate, + OperatorUpdateEnvelope, ResetRequired, RunCreated, RunSnapshot, @@ -52,12 +57,13 @@ RunStatusChanged, RunSummary, RunSummaryPage, - RunUpdate, - RunUpdateEnvelope, SequencedLogEntry, TraceDescriptor, TraceFinalized, + TraceHeader, + WorkflowDiscoveryDiagnostic, WorkflowInfo, + WorkflowTopology, ) from .registry import AmbiguousWorkflow, WorkflowRegistry from .result_store import ( @@ -89,6 +95,8 @@ _PROCESS_GROUP_POLL_INTERVAL_SECONDS = 0.02 DETAIL_PAGE_SIZE = 100 MAX_DETAIL_PAGE_SIZE = 500 +_DESCRIPTOR_PAGE_ORDER_FORWARD = 0 +_DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST = 1 STRUCTURAL_BASELINE_CAPACITY = 8 SUBSCRIBER_QUEUE_CAPACITY = 256 MAX_RUN_ID_BYTES = 256 @@ -97,6 +105,9 @@ MAX_TRACE_BODY_BYTES = 32 * 1024 * 1024 MAX_NODE_DETAIL_BYTES = 64 * 1024 * 1024 MAX_RUN_LOG_BYTES = 16 * 1024 * 1024 +_RELOAD_LOG_DIAGNOSTIC_LIMIT = 5 +_RELOAD_LOG_MESSAGE_LIMIT = 500 +_RELOAD_LOG_SUMMARY_LIMIT = 2_000 MAX_RUN_LOG_ENTRIES = 100_000 MAX_RUN_DETAIL_BYTES = 128 * 1024 * 1024 MAX_AGENT_DETAIL_DEPTH = 64 @@ -148,6 +159,7 @@ class _RunHandle: result_bundle: PendingResultBundle publication_event: threading.Event drain_thread: threading.Thread | None = None + preparation_thread: threading.Thread | None = None success_quiesced: bool = False @@ -166,7 +178,7 @@ class _RunNotifications: run_callbacks: tuple[tuple[Callable[[RunState], None], RunState], ...] log_callbacks: tuple[tuple[Callable[[LogEntry], None], LogEntry], ...] detail_callbacks: tuple[tuple[Callable[[DetailUpdate], None], DetailUpdate], ...] - update_subscribers: tuple[tuple[queue.Queue, tuple[RunUpdateEnvelope, ...]], ...] + update_subscribers: tuple[tuple[queue.Queue, tuple[OperatorUpdateEnvelope, ...]], ...] ready: threading.Event delivered: threading.Event @@ -196,6 +208,26 @@ class _RunDetailCapture: trace_invocation_ids: Mapping[str, str] +def _bound_reload_log_text(text: str) -> str: + if len(text) <= _RELOAD_LOG_SUMMARY_LIMIT: + return text + return text[: _RELOAD_LOG_SUMMARY_LIMIT - 3] + "..." + + +def _summarize_reload_diagnostics( + diagnostics: tuple[WorkflowDiscoveryDiagnostic, ...], +) -> str: + summaries = [ + f"{diagnostic.kind} {diagnostic.path}: " + f"{diagnostic.message[:_RELOAD_LOG_MESSAGE_LIMIT]}" + for diagnostic in diagnostics[:_RELOAD_LOG_DIAGNOSTIC_LIMIT] + ] + omitted = len(diagnostics) - len(summaries) + if omitted: + summaries.append(f"{omitted} additional diagnostic(s)") + return _bound_reload_log_text("; ".join(summaries)) + + class Operator: """Discover workflows and coordinate each local run in a spawned process.""" @@ -304,6 +336,7 @@ def __init__( self._run_revisions: dict[str, int] = {} self._node_revisions: dict[tuple[str, str], int] = {} self._logs: dict[str, list[SequencedLogEntry]] = {} + self._log_sequences_by_node: dict[str, dict[str, list[int]]] = {} self._agent_events: dict[tuple[str, str], list[AgentEvent]] = {} self._trace_descriptors: dict[tuple[str, str], TraceDescriptor] = {} self._trace_bodies: dict[tuple[str, str], dict[int, bytes]] = {} @@ -320,7 +353,7 @@ def __init__( self._update_subscribers: list[queue.Queue] = [] self._operator_instance_id = uuid4().hex self._sequence = 0 - self._stream_history: deque[RunUpdate] = deque(maxlen=stream_history_capacity) + self._stream_history: deque[OperatorUpdate] = deque(maxlen=stream_history_capacity) self._structural_baseline_capacity = structural_baseline_capacity self._structural_baselines: OrderedDict[int, _StructuralBaseline] = OrderedDict() self._lock = threading.RLock() @@ -368,8 +401,13 @@ def current_sequence(self) -> int: with self._lock: return self._sequence - def list_workflows(self) -> list[WorkflowInfo]: - workflows = self._registry.list_workflows() + def get_catalog(self) -> CatalogSnapshot: + """Return one complete, revisioned current-workflow catalog.""" + with self._lock: + return self._catalog_snapshot(self._registry.view, self._sequence) + + def _catalog_snapshot(self, view: CatalogView, as_of_sequence: int) -> CatalogSnapshot: + workflows = self._registry.list_workflows(view) for info in workflows: route = next( ( @@ -387,10 +425,20 @@ def list_workflows(self) -> list[WorkflowInfo]: nxt = self._scheduler.next_run_time(info.cron) info.next_run_at = nxt.timestamp() if nxt else None info.last_run_at = self._scheduler.last_triggered(info.workflow_id) - return workflows + return CatalogSnapshot( + revision=view.revision, + operator_instance_id=self._operator_instance_id, + as_of_sequence=as_of_sequence, + workflows=tuple(workflows), + scan_targets=view.scan_targets, + diagnostics=view.diagnostics, + ) + + def list_workflows(self) -> list[WorkflowInfo]: + return list(self.get_catalog().workflows) def list_diagnostics(self): - return self._registry.list_diagnostics() + return list(self.get_catalog().diagnostics) def list_runs(self, workflow_selector: str) -> list[RunState]: with self._lock: @@ -478,6 +526,28 @@ def get_run_snapshot( baseline = self._retained_structural_baseline_locked(as_of_sequence) return baseline.snapshots.get(run_id) + def get_latest_run_snapshot( + self, + run_id: str, + *, + operator_instance_id: str, + ) -> RunSnapshot | None: + """Return the latest structural run and detail watermarks atomically.""" + with self._lock: + if operator_instance_id != self._operator_instance_id: + raise StructuralBaselineUnavailableError( + "Operator instance changed; restart snapshot synchronization" + ) + run = self._runs.get(run_id) + if run is None: + return None + as_of_sequence = self._sequence + return self._run_snapshot_locked( + run, + summary=self._run_summary_locked(run), + as_of_sequence=as_of_sequence, + ) + def list_logs( self, run_id: str = "", @@ -485,9 +555,19 @@ def list_logs( page_token: str = "", after_sequence: int = 0, page_size: int = 0, + before_sequence: int = 0, + node_id: str = "", + order: int = _DESCRIPTOR_PAGE_ORDER_FORWARD, ) -> LogPage: """Return a byte-bounded page of immutable log body descriptors.""" size = _bounded_page_size(page_size) + order = _validated_descriptor_page_order(order) + after_sequence = _validated_descriptor_cursor(after_sequence, "after_sequence") + before_sequence = _validated_descriptor_cursor(before_sequence, "before_sequence") + if order == _DESCRIPTOR_PAGE_ORDER_FORWARD and before_sequence: + raise ValueError("before_sequence is only valid for newest-first pages") + if order == _DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST and after_sequence: + raise ValueError("after_sequence is only valid for forward pages") with self._lock: token = ( _decode_transport_token(page_token, "logs") @@ -497,20 +577,73 @@ def list_logs( self._validate_transport_token_locked(token) run_id = token["run_id"] through_sequence = token["through_sequence"] - cursor = token.get("cursor", after_sequence) + if "cursor" in token: + if token["order"] != order: + raise ValueError("Page order does not match the continuation token") + if token["node_id"] != node_id: + raise ValueError("Log node filter does not match the continuation token") + requested_cursor = ( + after_sequence + if order == _DESCRIPTOR_PAGE_ORDER_FORWARD + else before_sequence + ) + if requested_cursor and requested_cursor != token["cursor"]: + raise ValueError("Page cursor does not match the continuation token") + cursor = token["cursor"] + else: + cursor = ( + after_sequence + if order == _DESCRIPTOR_PAGE_ORDER_FORWARD + else before_sequence or through_sequence + 1 + ) logs = self._logs.get(run_id) if logs is None and run_id not in self._runs: raise KeyError(run_id) logs = logs or [] - start = min(cursor, len(logs)) - stop = min(start + size + 1, through_sequence, len(logs)) - candidates = logs[start:stop] - descriptors = [self._log_descriptor_locked(run_id, item) for item in candidates] + candidates: list[SequencedLogEntry] + if node_id: + run_node_sequences = self._log_sequences_by_node.get(run_id) + node_sequences = ( + () if run_node_sequences is None else run_node_sequences.get(node_id, ()) + ) + if order == _DESCRIPTOR_PAGE_ORDER_FORWARD: + start = bisect_right(node_sequences, cursor) + stop = bisect_right(node_sequences, through_sequence) + selected_sequences = node_sequences[start : min(start + size + 1, stop)] + else: + stop = bisect_right( + node_sequences, + min(cursor - 1, through_sequence), + ) + start = max(0, stop - size - 1) + selected_sequences = reversed(node_sequences[start:stop]) + candidates = [logs[sequence - 1] for sequence in selected_sequences] + elif order == _DESCRIPTOR_PAGE_ORDER_FORWARD: + start = min(cursor, len(logs)) + stop = min(start + size + 1, through_sequence, len(logs)) + candidates = logs[start:stop] + else: + start = min(cursor - 1, through_sequence, len(logs)) - 1 + stop = max(-1, start - size - 1) + candidates = [logs[index] for index in range(start, stop, -1)] + descriptors = [ + self._log_descriptor_locked( + run_id, + item, + as_of_sequence=token["as_of_sequence"], + ) + for item in candidates + ] selected = _take_bounded_descriptors(descriptors, size) next_page_token = "" - if selected and selected[-1].sequence < through_sequence: + if selected and len(selected) < len(descriptors): next_page_token = _encode_transport_token( - **{**token, "cursor": selected[-1].sequence} + **{ + **token, + "node_id": node_id, + "order": order, + "cursor": selected[-1].sequence, + } ) return LogPage( operator_instance_id=self._operator_instance_id, @@ -527,9 +660,22 @@ def list_agent_events( page_token: str = "", after_event_sequence: int = 0, page_size: int = 0, + before_event_sequence: int = 0, + order: int = _DESCRIPTOR_PAGE_ORDER_FORWARD, ) -> AgentEventPage: """Return a byte-bounded page of immutable event body descriptors.""" size = _bounded_page_size(page_size) + order = _validated_descriptor_page_order(order) + after_event_sequence = _validated_descriptor_cursor( + after_event_sequence, "after_event_sequence" + ) + before_event_sequence = _validated_descriptor_cursor( + before_event_sequence, "before_event_sequence" + ) + if order == _DESCRIPTOR_PAGE_ORDER_FORWARD and before_event_sequence: + raise ValueError("before_event_sequence is only valid for newest-first pages") + if order == _DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST and after_event_sequence: + raise ValueError("after_event_sequence is only valid for forward pages") with self._lock: token = ( _decode_transport_token(page_token, "events") @@ -540,30 +686,66 @@ def list_agent_events( run_id = token["run_id"] node_id = token["node_id"] through_sequence = token["through_sequence"] - cursor = token.get("cursor", after_event_sequence) + if "cursor" in token: + if token["order"] != order: + raise ValueError("Page order does not match the continuation token") + requested_cursor = ( + after_event_sequence + if order == _DESCRIPTOR_PAGE_ORDER_FORWARD + else before_event_sequence + ) + if requested_cursor and requested_cursor != token["cursor"]: + raise ValueError("Page cursor does not match the continuation token") + cursor = token["cursor"] + else: + cursor = ( + after_event_sequence + if order == _DESCRIPTOR_PAGE_ORDER_FORWARD + else before_event_sequence or through_sequence + 1 + ) run = self._runs.get(run_id) if run is None: raise KeyError(run_id) if node_id not in run.nodes: raise KeyError(node_id) events = self._agent_events.get((run_id, node_id), []) - start = bisect_right( - events, - cursor, - key=lambda item: item.event_sequence, - ) - stop = min(start + size + 1, len(events)) - candidates = events[start:stop] + if order == _DESCRIPTOR_PAGE_ORDER_FORWARD: + start = bisect_right( + events, + cursor, + key=lambda item: item.event_sequence, + ) + stop = min(start + size + 1, len(events)) + candidates = [ + item + for item in events[start:stop] + if item.event_sequence <= through_sequence + ] + else: + upper = bisect_right( + events, + min(cursor - 1, through_sequence), + key=lambda item: item.event_sequence, + ) + candidates = list(reversed(events[max(0, upper - size - 1) : upper])) descriptors = [ - self._agent_event_descriptor_locked(run_id, node_id, item) + self._agent_event_descriptor_locked( + run_id, + node_id, + item, + as_of_sequence=token["as_of_sequence"], + ) for item in candidates - if item.event_sequence <= through_sequence ] selected = _take_bounded_descriptors(descriptors, size) next_page_token = "" - if selected and selected[-1].event_sequence < through_sequence: + if selected and len(selected) < len(descriptors): next_page_token = _encode_transport_token( - **{**token, "cursor": selected[-1].event_sequence} + **{ + **token, + "order": order, + "cursor": selected[-1].event_sequence, + } ) return AgentEventPage( operator_instance_id=self._operator_instance_id, @@ -690,6 +872,10 @@ def _run_snapshot_locked( status=node.status, started_at=node.started_at, ended_at=node.ended_at, + running_elapsed_seconds=( + node.elapsed if node.status is NodeStatus.RUNNING else None + ), + error=node.error, trace=self._trace_descriptors.get((run.run_id, node.node_id)), revision=self._node_revisions.get( (run.run_id, node.node_id), @@ -718,6 +904,7 @@ def _run_snapshot_locked( run_id=run.run_id, through_sequence=latest_log_sequence, ), + topology=run.topology, ) def _current_log_page_token_locked(self, run_id: str) -> dict[str, Any]: @@ -770,13 +957,15 @@ def _validate_transport_token_locked(self, token: Mapping[str, Any]) -> None: if run is None: raise KeyError(run_id) node_id = token.get("node_id") - if node_id is not None and node_id not in run.nodes: + if node_id and node_id not in run.nodes: raise KeyError(node_id) def _log_descriptor_locked( self, run_id: str, item: SequencedLogEntry, + *, + as_of_sequence: int, ) -> LogRecordDescriptor: return LogRecordDescriptor( sequence=item.sequence, @@ -787,7 +976,7 @@ def _log_descriptor_locked( body_token=_encode_transport_token( kind="log-body", operator_instance_id=self._operator_instance_id, - as_of_sequence=self._sequence, + as_of_sequence=as_of_sequence, run_id=run_id, sequence=item.sequence, ), @@ -798,6 +987,8 @@ def _agent_event_descriptor_locked( run_id: str, node_id: str, item: AgentEvent, + *, + as_of_sequence: int, ) -> AgentEventDescriptor: return AgentEventDescriptor( invocation_id=item.invocation_id, @@ -806,11 +997,17 @@ def _agent_event_descriptor_locked( body_token=_encode_transport_token( kind="event-body", operator_instance_id=self._operator_instance_id, - as_of_sequence=self._sequence, + as_of_sequence=as_of_sequence, run_id=run_id, node_id=node_id, sequence=item.event_sequence, ), + event_kind=item.event_kind, + iteration=item.iteration, + duration_ms=item.duration_ms, + error=item.error, + tool_count=item.tool_count, + predict_count=item.predict_count, ) def _capture_run_detail_locked(self, run: RunState) -> _RunDetailCapture: @@ -896,6 +1093,7 @@ def _run_summary_locked(self, run: RunState) -> RunSummary: run_id=run.run_id, flow_name=run.flow_name, status=run.status, + triggered_at=run.triggered_at, started_at=run.started_at, ended_at=run.ended_at, triggered_by=run.triggered_by, @@ -922,7 +1120,7 @@ def _get_run_result_payload(self, run_id: str) -> EncodedWorkflowResult: if run is None: raise KeyError(run_id) status = run.status - if status in {RunStatus.PENDING, RunStatus.RUNNING}: + if status in {RunStatus.REQUESTING, RunStatus.PENDING, RunStatus.RUNNING}: raise RunResultNotReadyError(f"Run {run_id} is not terminal") if status != RunStatus.SUCCESS: raise RunResultUnavailableError( @@ -955,11 +1153,12 @@ def start_run( input: dict[str, Any] | None = None, context: dict[str, Any] | None = None, ) -> str: - """Synchronously prepare a live-source run before publishing its ID.""" + """Publish a requesting run, then prepare it asynchronously.""" if run_id is not None and not isinstance(run_id, str): raise InvalidRunIdError("run_id must be a string") if run_id and len(run_id.encode("utf-8")) > MAX_RUN_ID_BYTES: raise InvalidRunIdError(f"run_id exceeds {MAX_RUN_ID_BYTES}-byte UTF-8 limit") + triggered_at = time.time() descriptor, configured_root = self._registry.resolve_source(flow_name) import_root, workflow_relative_module_file = resolve_live_source( configured_root, descriptor.locator @@ -1016,6 +1215,7 @@ def start_run( # Reserve the ID before releasing the lock so concurrent callers # cannot create a second coordinator with the same caller-owned ID. self._active_runs[run_id] = handle + self._log_sequences_by_node.pop(run_id, None) try: with self._lock: if self._closed: @@ -1025,12 +1225,68 @@ def start_run( raise RuntimeError("Run coordinator did not expose a process ID") assign_process(windows_job, process.pid) assignment_event.set() + run = RunState( + run_id=run_id, + flow_name=descriptor.display_name, + status=RunStatus.REQUESTING, + triggered_at=triggered_at, + triggered_by=triggered_by, + workflow_id=descriptor.workflow_id, + workflow_display_name=descriptor.display_name, + ) + self._runs[run_id] = run + notifications = self._publish_run_locked(run) + self._wait_for_notifications(notifications) + preparation_thread = threading.Thread( + target=self._prepare_requested_run, + args=( + run_id, + descriptor.workflow_id, + descriptor.display_name, + triggered_by, + triggered_at, + handle, + ), + name=f"avalanche-prepare-{run_id}", + daemon=True, + ) + with self._lock: + if self._closed: + raise RuntimeError("Operator closed while creating run") + handle.preparation_thread = preparation_thread + preparation_thread.start() + return run_id + except BaseException: + cancel_event.set() + handle.publication_event.set() + handle.start_event.set() + _teardown_process_group(process, windows_job) + with self._lock: + self._runs.pop(run_id, None) + self._log_sequences_by_node.pop(run_id, None) + self._stored_results.pop(run_id, None) + self._active_runs.pop(run_id, None) + self._result_store.discard(result_bundle) + _close_event_queue(event_queue) + raise + + def _prepare_requested_run( + self, + run_id: str, + workflow_id: str, + catalog_display_name: str, + triggered_by: str, + triggered_at: float, + handle: _RunHandle, + ) -> None: + try: prepared, buffered_events = self._await_prepared(handle) - run = self._run_from_prepared( + prepared_run = self._run_from_prepared( run_id, - descriptor.workflow_id, - descriptor.display_name, + workflow_id, + catalog_display_name, triggered_by, + triggered_at, prepared, ) drain = threading.Thread( @@ -1040,28 +1296,67 @@ def start_run( daemon=True, ) with self._lock: + run = self._runs.get(run_id) + if run is None: + return if self._closed: raise RuntimeError("Operator closed while preparing run") + run.flow_name = prepared_run.flow_name + run.workflow_display_name = prepared_run.workflow_display_name + run.topology = prepared_run.topology + run.nodes = prepared_run.nodes + if handle.cancel_event.is_set(): + run.status = RunStatus.CANCELLED + run.ended_at = time.monotonic() + else: + run.status = RunStatus.PENDING handle.drain_thread = drain - drain.start() - self._runs[run_id] = run notifications = self._publish_run_locked(run) self._wait_for_notifications(notifications) + drain.start() handle.publication_event.set() - start_event.set() - return run_id - except BaseException: - cancel_event.set() - handle.publication_event.set() - start_event.set() - _teardown_process_group(process, windows_job) - with self._lock: - self._runs.pop(run_id, None) - self._stored_results.pop(run_id, None) - self._active_runs.pop(run_id, None) - self._result_store.discard(result_bundle) - _close_event_queue(event_queue) - raise + handle.start_event.set() + except BaseException as exc: + self._finish_requested_preparation_failure(run_id, handle, exc) + + def _finish_requested_preparation_failure( + self, + run_id: str, + handle: _RunHandle, + exc: BaseException, + ) -> None: + cancelled = handle.cancel_event.is_set() + entry = LogEntry( + timestamp=datetime.now(), + level=LogLevel.ERROR, + node_id="operator", + message=f"Workflow preparation failed: {exc}", + ) + with self._lock: + run = self._runs.get(run_id) + if run is None or run.status in { + RunStatus.SUCCESS, + RunStatus.FAILED, + RunStatus.CANCELLED, + }: + notifications = None + else: + run.status = RunStatus.CANCELLED if cancelled else RunStatus.FAILED + run.ended_at = time.monotonic() + log_entry = None + if not cancelled: + self._append_log_locked(run, entry) + log_entry = entry + notifications = self._publish_run_locked(run, log_entry=log_entry) + self._active_runs.pop(run_id, None) + handle.cancel_event.set() + handle.publication_event.set() + handle.start_event.set() + _teardown_process_group(handle.process, handle.windows_job) + self._result_store.discard(handle.result_bundle) + _close_event_queue(handle.event_queue) + if notifications is not None: + self._wait_for_notifications(notifications) def cancel_run(self, run_id: str) -> None: with self._lock: @@ -1073,7 +1368,11 @@ def cancel_run(self, run_id: str) -> None: handle.start_event.set() else: already_requested = True - if run is None or run.status not in (RunStatus.PENDING, RunStatus.RUNNING): + if run is None or run.status not in { + RunStatus.REQUESTING, + RunStatus.PENDING, + RunStatus.RUNNING, + }: return if handle is not None and not already_requested: threading.Thread( @@ -1098,7 +1397,7 @@ def on_detail_update(self, callback: Callable[[DetailUpdate], None]) -> None: def start_stream(self) -> None: """In-process callbacks are already live once registered.""" - def subscribe_run_updates( + def subscribe_operator_updates( self, operator_instance_id: str = "", after_sequence: int = 0 ) -> queue.Queue: """Atomically replay retained updates or require a structural reset.""" @@ -1124,7 +1423,7 @@ def subscribe_run_updates( for update in replay: subscription.put_nowait( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id=self._operator_instance_id, update=update, ) @@ -1139,9 +1438,9 @@ def _history_bounds_locked(self) -> tuple[int, int]: ) return history_floor, latest_sequence - def _update_reset_locked(self) -> RunUpdateEnvelope: + def _update_reset_locked(self) -> OperatorUpdateEnvelope: history_floor, latest_sequence = self._history_bounds_locked() - return RunUpdateEnvelope( + return OperatorUpdateEnvelope( operator_instance_id=self._operator_instance_id, reset_required=ResetRequired( history_floor=history_floor, @@ -1149,7 +1448,7 @@ def _update_reset_locked(self) -> RunUpdateEnvelope: ), ) - def unsubscribe_run_updates(self, subscription: queue.Queue) -> None: + def unsubscribe_operator_updates(self, subscription: queue.Queue) -> None: with self._lock: self._update_subscribers = [ item for item in self._update_subscribers if item is not subscription @@ -1183,6 +1482,10 @@ def close(self) -> None: delayed_drains = [] drain_deadline = time.monotonic() + 2.0 current_thread = threading.current_thread() + for _, handle in handles: + preparation = handle.preparation_thread + if preparation is not None and preparation is not current_thread: + preparation.join(timeout=max(0.0, drain_deadline - time.monotonic())) for run_id, handle in handles: drain = handle.drain_thread if drain is not None and drain is not current_thread: @@ -1301,34 +1604,74 @@ def _watch_loop(self) -> None: locators = tuple(descriptor.locator for descriptor in self._registry.descriptors()) source_roots = resolve_watch_roots(self._registry.configured_roots, locators) watch_dirs = tuple(str(path) for path in source_roots) - for changes in watch( - *watch_dirs, - stop_event=self._watcher_stop, - watch_filter=lambda _, path: is_source_path_included(path, source_roots), - rust_timeout=50, - yield_on_timeout=True, - ): - self._watcher_ready.set() - if not changes: - continue - changed_files = [path for _, path in changes] - logging.getLogger(__name__).info( - "Workflow files changed: %s, re-scanning...", changed_files - ) - self._refresh_workflows() - - def _refresh_workflows(self) -> None: + logger.info("Workflow watcher started: roots=%s", watch_dirs) + try: + for changes in watch( + *watch_dirs, + stop_event=self._watcher_stop, + watch_filter=lambda _, path: is_source_path_included(path, source_roots), + rust_timeout=50, + yield_on_timeout=True, + ): + self._watcher_ready.set() + if not changes: + continue + changed_files = tuple(sorted(path for _, path in changes)) + self._refresh_workflows(changed_files) + finally: + logger.info("Workflow watcher stopped") + + def _refresh_workflows(self, changed_files: tuple[str, ...] = ()) -> None: + previous = self._registry.view + logger.info( + "Workflow reload started: revision=%d changed_files=%s", + previous.revision, + changed_files, + ) # Publishing descriptors and replacing schedules are one logical update. # Otherwise an old cron can resolve newly-published same-ID source in the # small window between these two operations. with self._scheduler.reconciliation_boundary(): + view = self._registry.rescan(validate=routes_for) + failed_diagnostics = tuple( + diagnostic for diagnostic in view.diagnostics if diagnostic.kind != "skipped" + ) + if failed_diagnostics: + logger.warning( + "Workflow reload failed; retaining catalog revision %d: %s", + previous.revision, + _summarize_reload_diagnostics(failed_diagnostics), + ) + if view is previous: + if not failed_diagnostics: + logger.info( + "Workflow reload unchanged: revision=%d", + previous.revision, + ) + return try: - view = self._registry.rescan(validate=routes_for) - except ValueError as exc: - logging.getLogger(__name__).warning("Webhook catalog refresh rejected: %s", exc) + self._scheduler.reconcile(view.by_id.values()) + self._reconcile_webhooks(view.by_id.values()) + except OSError as exc: + self._registry.restore_view(view, previous) + self._scheduler.reconcile(previous.by_id.values()) + self._reconcile_webhooks(previous.by_id.values()) + error = _bound_reload_log_text(f"{type(exc).__name__}: {exc}") + logger.warning( + "Workflow reload reconciliation failed; retaining catalog " + "revision %d: %s", + previous.revision, + error, + ) return - self._scheduler.reconcile(view.by_id.values()) - self._reconcile_webhooks(view.by_id.values()) + self._publish_catalog(view) + if not failed_diagnostics: + logger.info( + "Workflow reload succeeded: revision=%d->%d workflows=%d", + previous.revision, + view.revision, + len(view.by_id), + ) def _reconcile_webhooks(self, descriptors) -> None: routes = routes_for(tuple(descriptors)) @@ -1344,6 +1687,8 @@ def _await_prepared( try: event = handle.event_queue.get(timeout=0.1) except queue.Empty: + if handle.cancel_event.is_set(): + raise RuntimeError("Run preparation cancelled") if not handle.process.is_alive(): raise RuntimeError( f"Run coordinator exited during preparation (exit code " @@ -1366,18 +1711,44 @@ def _run_from_prepared( workflow_id: str, catalog_display_name: str, triggered_by: str, + triggered_at: float, prepared: dict[str, Any], ) -> RunState: display_name = prepared.get("display_name") or catalog_display_name + node_ids = tuple(prepared["node_ids"]) + topology = WorkflowTopology( + node_ids=node_ids, + graph=tuple( + (node_id, tuple(prepared["graph"].get(node_id, ()))) for node_id in node_ids + ), + node_types=tuple( + (node_id, prepared["node_types"][node_id]) for node_id in node_ids + ), + display_names=tuple( + (node_id, prepared["display_names"][node_id]) for node_id in node_ids + ), + agent_field_schemas_json=tuple( + (node_id, prepared["agent_field_schemas_json"][node_id]) + for node_id in node_ids + if node_id in prepared["agent_field_schemas_json"] + ), + agent_instruction_lines=tuple( + (node_id, prepared["agent_instruction_lines"][node_id]) + for node_id in node_ids + if node_id in prepared["agent_instruction_lines"] + ), + ) run = RunState( run_id=run_id, flow_name=display_name, workflow_id=workflow_id, workflow_display_name=display_name, + topology=topology, status=RunStatus.PENDING, triggered_by=triggered_by, + triggered_at=triggered_at, ) - for node_id in prepared["node_ids"]: + for node_id in node_ids: run.nodes[node_id] = NodeState( node_id=node_id, name=prepared["display_names"][node_id], @@ -1539,6 +1910,7 @@ def _apply_event( node.started_at = event["timestamp"] else: node.ended_at = event["timestamp"] + node.error = event["error"] if status == NodeStatus.FAILED else None changed_node_ids = (node.node_id,) status_node_ids = changed_node_ids mutated = True @@ -1572,10 +1944,20 @@ def _apply_event( RunStatus.CANCELLED, }: return False + log_node_id = event["node_id"] + if log_node_id not in run.nodes: + matches = ( + node.node_id + for node in run.nodes.values() + if node.name == log_node_id + ) + matched_node_id = next(matches, None) + if matched_node_id is not None and next(matches, None) is None: + log_node_id = matched_node_id log_entry = LogEntry( timestamp=datetime.fromtimestamp(event["timestamp"]), level=_LEVEL_MAP.get(event["level"], LogLevel.INFO), - node_id=event["node_id"], + node_id=log_node_id, message=event["message"], ) self._append_log_locked(run, log_entry) @@ -1722,11 +2104,21 @@ def _record_agent_evidence_event_locked( raise _CoordinatorProtocolError( f"agent event exceeds {self._max_agent_event_bytes} byte limit" ) + iteration = data.get("iteration") + duration_ms = data.get("duration_ms") + tool_count = data.get("tool_count") + predict_count = data.get("predict_count") projected_agent_event = AgentEvent( invocation_id=invocation_id, event_sequence=len(projected_events) + 1, event_json=event_json, size_bytes=event_size, + event_kind=event_kind, + iteration=iteration if isinstance(iteration, int) else None, + duration_ms=duration_ms if isinstance(duration_ms, int) else None, + error=bool(data.get("error")), + tool_count=tool_count if isinstance(tool_count, int) else 0, + predict_count=predict_count if isinstance(predict_count, int) else 0, ) detail = [] if data.get("iteration") is not None: @@ -1754,14 +2146,25 @@ def _record_agent_evidence_event_locked( if not isinstance(trace, dict): return None _validate_agent_detail_depth(trace) + header = _trace_header_from_payload(trace) + trace_header = { + name: value + for name, value in trace.items() + if name not in {"steps", "evidence"} + } + evidence = trace.get("evidence") + if isinstance(evidence, dict): + trace_header["evidence"] = { + name: value for name, value in evidence.items() if name != "events" + } finalized_trace = json.dumps( - trace, + trace_header, default=str, separators=(",", ":"), ).encode() if len(finalized_trace) > self._max_trace_body_bytes: raise _CoordinatorProtocolError( - f"agent trace exceeds {self._max_trace_body_bytes} byte limit" + f"agent trace header exceeds {self._max_trace_body_bytes} byte limit" ) versions = self._trace_bodies.get(key, {}) if ( @@ -1772,7 +2175,6 @@ def _record_agent_evidence_event_locked( return None status = str(trace.get("status") or "unavailable")[:80] error = None - evidence = trace.get("evidence") descriptor = TraceDescriptor( status=status, revision=previous_descriptor.revision, @@ -1783,6 +2185,7 @@ def _record_agent_evidence_event_locked( latest_event_sequence=( projected_events[-1].event_sequence if projected_events else 0 ), + header=header, ) message = f"Agent trace {status}" if status == "error": @@ -1880,13 +2283,16 @@ def _append_log_unchecked_locked( size_bytes: int, ) -> None: logs = self._logs.setdefault(run.run_id, []) + sequence = len(logs) + 1 logs.append( SequencedLogEntry( - sequence=len(logs) + 1, + sequence=sequence, entry=deepcopy(entry), size_bytes=size_bytes, ) ) + node_sequences = self._log_sequences_by_node.setdefault(run.run_id, {}) + node_sequences.setdefault(entry.node_id, []).append(sequence) self._run_log_bytes[run.run_id] = self._run_log_bytes.get(run.run_id, 0) + size_bytes self._run_detail_bytes[run.run_id] = ( self._run_detail_bytes.get(run.run_id, 0) + size_bytes @@ -2062,7 +2468,9 @@ def _publish_run_locked( summary=summary, as_of_sequence=publication_sequence, ) - changes.append(RunCreated(summary=summary, nodes=snapshot.nodes)) + changes.append( + RunCreated(summary=summary, nodes=snapshot.nodes, topology=snapshot.topology) + ) else: if summary_changed: changes.append( @@ -2083,7 +2491,11 @@ def _publish_run_locked( status=node.status, started_at=node.started_at, ended_at=node.ended_at, + running_elapsed_seconds=( + node.elapsed if node.status is NodeStatus.RUNNING else None + ), revision=publication_sequence, + error=node.error, ) ) if log_entry is not None: @@ -2091,7 +2503,11 @@ def _publish_run_locked( changes.append( LogAppended( run_id=run.run_id, - log=self._log_descriptor_locked(run.run_id, log_item), + log=self._log_descriptor_locked( + run.run_id, + log_item, + as_of_sequence=publication_sequence, + ), ) ) for node_id, event in agent_events.items(): @@ -2103,6 +2519,7 @@ def _publish_run_locked( run.run_id, node_id, event, + as_of_sequence=publication_sequence, ), ) ) @@ -2118,14 +2535,14 @@ def _publish_run_locked( updates = [] for change in changes: self._sequence += 1 - update = RunUpdate(sequence=self._sequence, change=change) + update = OperatorUpdate(sequence=self._sequence, change=change) self._stream_history.append(update) updates.append(update) if self._sequence != publication_sequence: raise RuntimeError("Run publication produced an inconsistent update batch") envelopes = tuple( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id=self._operator_instance_id, update=update, ) @@ -2193,6 +2610,33 @@ def _notify_run(self, run: RunState, *, summary_changed: bool = True) -> None: ) self._wait_for_notifications(notifications) + def _publish_catalog(self, view: CatalogView) -> None: + with self._lock: + self._sequence += 1 + catalog = self._catalog_snapshot(view, self._sequence) + update = OperatorUpdate( + sequence=self._sequence, + change=CatalogReplaced(catalog=catalog), + ) + self._stream_history.append(update) + envelope = OperatorUpdateEnvelope( + operator_instance_id=self._operator_instance_id, + update=update, + ) + notifications = _RunNotifications( + sequence=self._sequence, + run_callbacks=(), + detail_callbacks=(), + log_callbacks=(), + update_subscribers=tuple( + (subscription, (envelope,)) for subscription in self._update_subscribers + ), + ready=threading.Event(), + delivered=threading.Event(), + ) + self._notification_queue.put_nowait(notifications) + self._wait_for_notifications(notifications) + def _wait_for_notifications(self, notifications: _RunNotifications) -> None: notifications.ready.set() if threading.current_thread() is self._notification_thread: @@ -2232,7 +2676,7 @@ def _deliver_notifications(self, notifications: _RunNotifications) -> None: def _deliver_update_batch( self, subscription: queue.Queue, - envelopes: tuple[RunUpdateEnvelope, ...], + envelopes: tuple[OperatorUpdateEnvelope, ...], ) -> None: with self._lock: if subscription not in self._update_subscribers: @@ -2254,6 +2698,21 @@ def _bounded_page_size(page_size: int) -> int: return min(page_size or DETAIL_PAGE_SIZE, MAX_DETAIL_PAGE_SIZE) +def _validated_descriptor_page_order(order: int) -> int: + if type(order) is not int or order not in { + _DESCRIPTOR_PAGE_ORDER_FORWARD, + _DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + }: + raise ValueError("Invalid descriptor page order") + return order + + +def _validated_descriptor_cursor(cursor: int, field_name: str) -> int: + if type(cursor) is not int or cursor < 0: + raise ValueError(f"{field_name} must be a non-negative integer") + return cursor + + def _encode_page_token( *, operator_instance_id: str, @@ -2330,13 +2789,27 @@ def _decode_transport_token( or type(value.get("run_id")) is not str ): raise ValueError("Invalid detail token") + if value["as_of_sequence"] < 0: + raise ValueError("Invalid detail token") if value["kind"] in {"logs", "events"}: - if type(value.get("through_sequence")) is not int: - raise ValueError("Invalid detail token") - if "cursor" in value and type(value["cursor"]) is not int: + if type(value.get("through_sequence")) is not int or value["through_sequence"] < 0: raise ValueError("Invalid detail token") + if "cursor" in value: + if ( + type(value["cursor"]) is not int + or value["cursor"] < 0 + or type(value.get("order")) is not int + or value["order"] + not in { + _DESCRIPTOR_PAGE_ORDER_FORWARD, + _DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + } + ): + raise ValueError("Invalid detail token") + if value["kind"] == "logs" and type(value.get("node_id")) is not str: + raise ValueError("Invalid detail token") else: - if type(value.get("sequence")) is not int: + if type(value.get("sequence")) is not int or value["sequence"] < 1: raise ValueError("Invalid detail token") if value["kind"] in {"events", "event-body"} and type(value.get("node_id")) is not str: raise ValueError("Invalid detail token") @@ -2399,8 +2872,11 @@ def _materialize_run_detail(capture: _RunDetailCapture) -> RunState: run = capture.run run.logs = [deepcopy(item.entry) for item in capture.logs] for node_id, node in run.nodes.items(): + trace_invocation_id = capture.trace_invocation_ids.get(node_id) projected_events = [] for event in capture.events.get(node_id, ()): + if trace_invocation_id and event.invocation_id != trace_invocation_id: + continue try: projected = json.loads(event.event_json) except (TypeError, ValueError): @@ -2418,9 +2894,31 @@ def _materialize_run_detail(capture: _RunDetailCapture) -> RunState: decoded = None if isinstance(decoded, dict): trace = decoded + steps = [] + evidence_events = [] + for projected in projected_events: + data = projected.get("data") + if ( + projected.get("event_kind") == "iteration.recorded" + and isinstance(data, dict) + and isinstance(data.get("step"), dict) + ): + steps.append(data["step"]) + evidence_events.append( + { + "sequence": projected.get("sequence"), + "kind": projected.get("event_kind"), + "timestamp_ns": projected.get("timestamp_ns"), + "data": data if isinstance(data, dict) else {}, + } + ) + trace["steps"] = steps + evidence = trace.get("evidence") + if isinstance(evidence, dict): + evidence["events"] = evidence_events envelope = { "schema_version": 1, - "invocation_id": capture.trace_invocation_ids.get(node_id) or None, + "invocation_id": trace_invocation_id or None, "status": descriptor.status if descriptor is not None else "in_progress", "run_id": ( trace.get("evidence", {}).get("run_id") @@ -2460,6 +2958,8 @@ def _replace_queue_contents(subscription: queue.Queue, item: Any) -> None: _MAX_EVENT_EDGES = 100_000 _MAX_EVENT_FIELD_LENGTH = 4096 _MAX_EVENT_MESSAGE_LENGTH = 65_536 +_MAX_EVENT_AGENT_FIELD_SCHEMA_BYTES = 1024 * 1024 +_MAX_EVENT_AGENT_FIELD_SCHEMAS_TOTAL_BYTES = 16 * 1024 * 1024 _MAX_EVENT_TRACEBACK_LENGTH = 262_144 _MAX_EVENT_TIMESTAMP_MAGNITUDE = 10**12 @@ -2497,6 +2997,68 @@ def walk(item: object, depth: int) -> None: walk(value, 0) +def _trace_header_from_payload(trace: dict[str, Any]) -> TraceHeader | None: + """Validate the stable PredictRLM RunTrace header at the coordinator boundary.""" + if "model" not in trace: + return None + + status = trace.get("status") + if type(status) is not str or not status or len(status) > _MAX_EVENT_FIELD_LENGTH: + raise _CoordinatorProtocolError( + "agent trace header field 'status' must be a non-empty bounded string" + ) + model = trace.get("model") + if type(model) is not str or not model or len(model) > _MAX_EVENT_FIELD_LENGTH: + raise _CoordinatorProtocolError( + "agent trace header field 'model' must be a non-empty bounded string" + ) + sub_model = trace.get("sub_model") + if sub_model is not None and ( + type(sub_model) is not str or len(sub_model) > _MAX_EVENT_FIELD_LENGTH + ): + raise _CoordinatorProtocolError( + "agent trace header field 'sub_model' must be a bounded string or null" + ) + + iterations = trace.get("iterations") + if type(iterations) is not int or iterations < 0: + raise _CoordinatorProtocolError( + "agent trace header field 'iterations' must be a non-negative integer" + ) + max_iterations = trace.get("max_iterations") + if type(max_iterations) is not int or max_iterations < 0: + raise _CoordinatorProtocolError( + "agent trace header field 'max_iterations' must be a non-negative integer" + ) + duration_ms = trace.get("duration_ms") + if type(duration_ms) is not int or duration_ms < 0: + raise _CoordinatorProtocolError( + "agent trace header field 'duration_ms' must be a non-negative integer" + ) + + usage = trace.get("usage") + if not isinstance(usage, dict): + raise _CoordinatorProtocolError("agent trace header field 'usage' must be an object") + telemetry = trace.get("telemetry_ref") + if telemetry is not None and not isinstance(telemetry, dict): + raise _CoordinatorProtocolError( + "agent trace header field 'telemetry_ref' must be an object or null" + ) + + return TraceHeader( + status=status, + model=model, + sub_model=sub_model, + iterations=iterations, + max_iterations=max_iterations, + duration_ms=duration_ms, + usage_json=json.dumps(usage, separators=(",", ":")), + telemetry_json=( + json.dumps(telemetry, separators=(",", ":")) if telemetry is not None else None + ), + ) + + def _validate_preparation_event(event: object) -> str: event_type = _event_type(event) if event_type == "prepared": @@ -2509,6 +3071,8 @@ def _validate_preparation_event(event: object) -> str: "node_types", "display_names", "display_name", + "agent_field_schemas_json", + "agent_instruction_lines", }, ) node_ids = _required_field(event, "node_ids") @@ -2526,6 +3090,10 @@ def _validate_preparation_event(event: object) -> str: _graph_mapping(event, "graph") node_types = _string_mapping(event, "node_types") display_names = _string_mapping(event, "display_names") + agent_field_schemas_json = _agent_field_schema_mapping( + event, "agent_field_schemas_json" + ) + agent_instruction_lines = _string_mapping(event, "agent_instruction_lines") for node_id in node_ids: if node_id not in node_types: raise _CoordinatorProtocolError( @@ -2535,6 +3103,20 @@ def _validate_preparation_event(event: object) -> str: raise _CoordinatorProtocolError( f"field 'display_names' is missing node {_bounded_ascii(node_id)}" ) + unknown_agent_nodes = set(agent_field_schemas_json).difference(node_ids) + if unknown_agent_nodes: + unknown = min(unknown_agent_nodes) + raise _CoordinatorProtocolError( + f"field 'agent_field_schemas_json' references unknown node " + f"{_bounded_ascii(unknown)}" + ) + unknown_instruction_nodes = set(agent_instruction_lines).difference(node_ids) + if unknown_instruction_nodes: + unknown = min(unknown_instruction_nodes) + raise _CoordinatorProtocolError( + f"field 'agent_instruction_lines' references unknown node " + f"{_bounded_ascii(unknown)}" + ) display_name = event.get("display_name") if display_name is not None and ( type(display_name) is not str or len(display_name) > _MAX_EVENT_FIELD_LENGTH @@ -2697,7 +3279,12 @@ def _timestamp_field(event: dict[str, Any], field: str) -> float | int: raise _CoordinatorProtocolError(f"field {field!r} must be a bounded finite number") -def _string_mapping(event: dict[str, Any], field: str) -> Mapping[str, str]: +def _string_mapping( + event: dict[str, Any], + field: str, + *, + maximum_value_length: int | None = _MAX_EVENT_FIELD_LENGTH, +) -> Mapping[str, str]: value = _required_field(event, field) if ( type(value) is not dict @@ -2706,11 +3293,60 @@ def _string_mapping(event: dict[str, Any], field: str) -> Mapping[str, str]: type(key) is not str or type(item) is not str or len(key) > _MAX_EVENT_FIELD_LENGTH - or len(item) > _MAX_EVENT_FIELD_LENGTH + or (maximum_value_length is not None and len(item) > maximum_value_length) for key, item in value.items() ) ): - raise _CoordinatorProtocolError(f"field {field!r} must map strings to strings") + raise _CoordinatorProtocolError(f"field {field!r} must map bounded strings to strings") + return value + + +def _agent_field_schema_mapping(event: dict[str, Any], field: str) -> Mapping[str, str]: + value = _string_mapping(event, field, maximum_value_length=None) + total_bytes = 0 + for schema_json in value.values(): + try: + encoded_size = len(schema_json.encode("utf-8")) + schema = json.loads(schema_json) + except (UnicodeEncodeError, json.JSONDecodeError) as exc: + raise _CoordinatorProtocolError( + f"field {field!r} values must be UTF-8 JSON objects" + ) from exc + if encoded_size > _MAX_EVENT_AGENT_FIELD_SCHEMA_BYTES: + raise _CoordinatorProtocolError( + f"field {field!r} values must not exceed " + f"{_MAX_EVENT_AGENT_FIELD_SCHEMA_BYTES} UTF-8 bytes" + ) + total_bytes += encoded_size + if type(schema) is not dict or set(schema) != {"inputs", "outputs"}: + raise _CoordinatorProtocolError( + f"field {field!r} values must contain only input and output schemas" + ) + for schemas in schema.values(): + if type(schemas) is not list or len(schemas) > _MAX_EVENT_NODES: + raise _CoordinatorProtocolError( + f"field {field!r} inputs and outputs must be bounded lists" + ) + if any( + type(item) is not dict + or set(item) != {"name", "type", "description"} + or type(item["name"]) is not str + or not item["name"] + or len(item["name"]) > _MAX_EVENT_FIELD_LENGTH + or type(item["type"]) is not str + or len(item["type"]) > _MAX_EVENT_FIELD_LENGTH + or type(item["description"]) is not str + or len(item["description"]) > _MAX_EVENT_MESSAGE_LENGTH + for item in schemas + ): + raise _CoordinatorProtocolError( + f"field {field!r} contains an invalid invocation field schema" + ) + if total_bytes > _MAX_EVENT_AGENT_FIELD_SCHEMAS_TOTAL_BYTES: + raise _CoordinatorProtocolError( + f"field {field!r} must not exceed " + f"{_MAX_EVENT_AGENT_FIELD_SCHEMAS_TOTAL_BYTES} total UTF-8 bytes" + ) return value diff --git a/src/runtime/operator/proto/operator.proto b/src/runtime/operator/proto/operator.proto index 02602f1..9149103 100644 --- a/src/runtime/operator/proto/operator.proto +++ b/src/runtime/operator/proto/operator.proto @@ -9,17 +9,18 @@ package avalanche.operator; // ── Service ───────────────────────────────────────────── service OperatorService { - rpc ListFlows(Empty) returns (FlowList); + rpc GetCatalog(Empty) returns (CatalogSnapshotMsg); rpc StartRun(StartRunRequest) returns (StartRunResponse); rpc CancelRun(CancelRunRequest) returns (Empty); rpc GetRunResult(GetRunRequest) returns (RunResultMsg); rpc ListRunSummaries(ListRunSummariesRequest) returns (RunSummaryPage); rpc GetRunSnapshot(GetRunSnapshotRequest) returns (RunSnapshotMsg); + rpc GetLatestRunSnapshot(GetLatestRunSnapshotRequest) returns (RunSnapshotMsg); rpc ListLogs(ListLogsRequest) returns (LogPage); rpc ListAgentEvents(ListAgentEventsRequest) returns (AgentEventPage); rpc ReadTrace(ReadTraceRequest) returns (stream TraceChunk); rpc ReadDetail(ReadDetailRequest) returns (stream DetailChunk); - rpc StreamRunUpdates(StreamRunUpdatesRequest) returns (stream RunUpdateEnvelope); + rpc StreamOperatorUpdates(StreamOperatorUpdatesRequest) returns (stream OperatorUpdateEnvelope); } // ── Request / Response ────────────────────────────────── @@ -27,7 +28,7 @@ service OperatorService { message Empty {} message StartRunRequest { - string flow_name = 1; + reserved 1; string input_json = 2; string context_json = 3; repeated FileAttachment input_files = 4; @@ -68,23 +69,41 @@ message GetRunSnapshotRequest { uint64 as_of_sequence = 3; } +message GetLatestRunSnapshotRequest { + string run_id = 1; + string operator_instance_id = 2; +} + +enum DescriptorPageOrder { + DESCRIPTOR_PAGE_ORDER_FORWARD = 0; + DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST = 1; +} + // Page tokens are opaque bearer references issued by GetRunSnapshot. The current // loopback transport does not sign them; authenticated deployments must sign or // tenant-bind tokens and reauthorize the referenced run on every use. message ListLogsRequest { - // Required snapshot-issued token. after_sequence is relative to this snapshot. + // Required snapshot-issued token. Cursors and filters are relative to this snapshot. string page_token = 1; - // Exclusive log cursor within the snapshot identified by page_token. + // Exclusive lower log bound for forward and incremental hydration. uint64 after_sequence = 2; uint32 page_size = 3; + // Exclusive upper log bound for newest-first hydration; zero starts at the snapshot end. + uint64 before_sequence = 4; + // Optional exact node filter. Continuation tokens bind this filter. + string node_id = 5; + DescriptorPageOrder order = 6; } message ListAgentEventsRequest { - // Required snapshot-issued token. after_event_sequence is relative to this snapshot. + // Required snapshot-issued token. Cursors are relative to this snapshot. string page_token = 1; - // Exclusive event cursor within the snapshot identified by page_token. + // Exclusive lower event bound for forward and incremental hydration. uint64 after_event_sequence = 2; uint32 page_size = 3; + // Exclusive upper event bound for newest-first hydration; zero starts at the snapshot end. + uint64 before_event_sequence = 4; + DescriptorPageOrder order = 5; } message ReadTraceRequest { @@ -98,7 +117,7 @@ message ReadDetailRequest { string body_token = 1; } -message StreamRunUpdatesRequest { +message StreamOperatorUpdatesRequest { string operator_instance_id = 1; uint64 after_sequence = 2; } @@ -109,6 +128,15 @@ message NodeEdges { repeated string children = 1; } +message WorkflowTopologyMsg { + repeated string node_ids = 1; + map graph = 2; + map node_types = 3; + map display_names = 4; + map agent_field_schemas_json = 5; + map agent_instruction_lines = 6; +} + message FlowInfoMsg { string name = 1; string file_path = 2; @@ -131,10 +159,6 @@ message FlowInfoMsg { bool webhook_active = 19; } -message FlowList { - repeated FlowInfoMsg flows = 1; - repeated DiscoveryDiagnosticMsg diagnostics = 2; -} message DiscoveryDiagnosticMsg { string path = 1; @@ -142,6 +166,20 @@ message DiscoveryDiagnosticMsg { string message = 3; } +message ScanTargetMsg { + string alias = 1; + string target_path = 2; + string kind = 3; +} +message CatalogSnapshotMsg { + string operator_instance_id = 1; + uint64 as_of_sequence = 2; + uint64 revision = 3; + repeated FlowInfoMsg workflows = 4; + repeated ScanTargetMsg scan_targets = 5; + repeated DiscoveryDiagnosticMsg diagnostics = 6; +} + message ResultFileAttachment { string attachment_id = 1; optional string name = 2; @@ -166,8 +204,21 @@ message RunSummaryMsg { string workflow_display_name = 8; uint64 created_sequence = 9; uint64 revision = 10; + double triggered_at = 11; +} + +message TraceHeaderMsg { + string status = 1; + string model = 2; + optional string sub_model = 3; + uint64 iterations = 4; + uint64 max_iterations = 5; + uint64 duration_ms = 6; + string usage_json = 7; + optional string telemetry_json = 8; } + message TraceDescriptorMsg { string status = 1; uint64 revision = 2; @@ -176,6 +227,7 @@ message TraceDescriptorMsg { uint64 event_count = 5; uint64 size_bytes = 6; uint64 latest_event_sequence = 7; + TraceHeaderMsg header = 8; } message NodeSnapshotMsg { @@ -188,6 +240,8 @@ message NodeSnapshotMsg { TraceDescriptorMsg trace = 7; uint64 revision = 8; string event_page_token = 9; + optional string error = 10; + optional double running_elapsed_seconds = 11; } message RunSnapshotMsg { @@ -197,6 +251,7 @@ message RunSnapshotMsg { repeated NodeSnapshotMsg nodes = 4; uint64 latest_log_sequence = 5; string log_page_token = 6; + WorkflowTopologyMsg topology = 7; } message RunSummaryPage { @@ -227,6 +282,12 @@ message AgentEventDescriptorMsg { uint64 size_bytes = 2; string body_token = 3; string invocation_id = 4; + string event_kind = 5; + optional uint32 iteration = 6; + optional uint64 duration_ms = 7; + bool error = 8; + uint32 tool_count = 9; + uint32 predict_count = 10; } message AgentEventPage { @@ -254,6 +315,7 @@ message DetailChunk { message RunCreated { RunSummaryMsg summary = 1; repeated NodeSnapshotMsg nodes = 2; + WorkflowTopologyMsg topology = 3; } message RunStatusChanged { @@ -271,6 +333,8 @@ message NodeStatusChanged { double started_at = 4; double ended_at = 5; uint64 revision = 6; + optional string error = 7; + optional double running_elapsed_seconds = 8; } message LogAppended { @@ -290,7 +354,11 @@ message TraceFinalized { TraceDescriptorMsg trace = 3; } -message RunUpdate { +message CatalogReplaced { + CatalogSnapshotMsg catalog = 1; +} + +message OperatorUpdate { uint64 sequence = 1; oneof change { RunCreated run_created = 2; @@ -299,6 +367,7 @@ message RunUpdate { LogAppended log_appended = 5; AgentEventAppended agent_event_appended = 6; TraceFinalized trace_finalized = 7; + CatalogReplaced catalog_replaced = 8; } } @@ -307,10 +376,10 @@ message ResetRequired { uint64 latest_sequence = 2; } -message RunUpdateEnvelope { +message OperatorUpdateEnvelope { string operator_instance_id = 1; oneof payload { - RunUpdate update = 2; + OperatorUpdate update = 2; ResetRequired reset_required = 3; } } diff --git a/src/runtime/operator/proto/operator_pb2.py b/src/runtime/operator/proto/operator_pb2.py index fb0c1b7..3a9e728 100644 --- a/src/runtime/operator/proto/operator_pb2.py +++ b/src/runtime/operator/proto/operator_pb2.py @@ -24,13 +24,23 @@ -DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0eoperator.proto\x12\x12\x61valanche.operator\"\x07\n\x05\x45mpty\"\xb2\x01\n\x0fStartRunRequest\x12\x11\n\tflow_name\x18\x01 \x01(\t\x12\x12\n\ninput_json\x18\x02 \x01(\t\x12\x14\n\x0c\x63ontext_json\x18\x03 \x01(\t\x12\x37\n\x0binput_files\x18\x04 \x03(\x0b\x32\".avalanche.operator.FileAttachment\x12\x0e\n\x06run_id\x18\x06 \x01(\t\x12\x19\n\x11workflow_selector\x18\x07 \x01(\t\"i\n\x0e\x46ileAttachment\x12\x12\n\nfield_name\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\x12\x14\n\x0c\x63ontent_type\x18\x04 \x01(\t\x12\x0e\n\x06sha256\x18\x05 \x01(\t\"\"\n\x10StartRunResponse\x12\x0e\n\x06run_id\x18\x01 \x01(\t\"\"\n\x10\x43\x61ncelRunRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\"\x1f\n\rGetRunRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\"[\n\x17ListRunSummariesRequest\x12\x19\n\x11workflow_selector\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\r\x12\x12\n\npage_token\x18\x03 \x01(\t\"]\n\x15GetRunSnapshotRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x1c\n\x14operator_instance_id\x18\x02 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x03 \x01(\x04\"P\n\x0fListLogsRequest\x12\x12\n\npage_token\x18\x01 \x01(\t\x12\x16\n\x0e\x61\x66ter_sequence\x18\x02 \x01(\x04\x12\x11\n\tpage_size\x18\x03 \x01(\r\"]\n\x16ListAgentEventsRequest\x12\x12\n\npage_token\x18\x01 \x01(\t\x12\x1c\n\x14\x61\x66ter_event_sequence\x18\x02 \x01(\x04\x12\x11\n\tpage_size\x18\x03 \x01(\r\"c\n\x10ReadTraceRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12\x10\n\x08revision\x18\x03 \x01(\x04\x12\x1c\n\x14operator_instance_id\x18\x04 \x01(\t\"\'\n\x11ReadDetailRequest\x12\x12\n\nbody_token\x18\x01 \x01(\t\"O\n\x17StreamRunUpdatesRequest\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61\x66ter_sequence\x18\x02 \x01(\x04\"\x1d\n\tNodeEdges\x12\x10\n\x08\x63hildren\x18\x01 \x03(\t\"\xcd\x06\n\x0b\x46lowInfoMsg\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\tfile_path\x18\x02 \x01(\t\x12\x10\n\x08node_ids\x18\x03 \x03(\t\x12\x39\n\x05graph\x18\x04 \x03(\x0b\x32*.avalanche.operator.FlowInfoMsg.GraphEntry\x12\x42\n\nnode_types\x18\x05 \x03(\x0b\x32..avalanche.operator.FlowInfoMsg.NodeTypesEntry\x12H\n\rdisplay_names\x18\x06 \x03(\x0b\x32\x31.avalanche.operator.FlowInfoMsg.DisplayNamesEntry\x12\x0c\n\x04\x63ron\x18\x07 \x01(\t\x12\x13\n\x0bnext_run_at\x18\x08 \x01(\x01\x12\x13\n\x0blast_run_at\x18\t \x01(\x01\x12\x13\n\x0bworkflow_id\x18\n \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x0b \x01(\t\x12\x12\n\nroot_alias\x18\x0c \x01(\t\x12\x15\n\rrelative_file\x18\r \x01(\t\x12\x16\n\x0e\x62uilder_symbol\x18\x0e \x01(\t\x12\x16\n\x0e\x61gent_node_ids\x18\x0f \x03(\t\x12S\n\x13\x61gent_metadata_json\x18\x10 \x03(\x0b\x32\x36.avalanche.operator.FlowInfoMsg.AgentMetadataJsonEntry\x12\x14\n\x0cwebhook_path\x18\x11 \x01(\t\x12\x13\n\x0bwebhook_url\x18\x12 \x01(\t\x12\x16\n\x0ewebhook_active\x18\x13 \x01(\x08\x1aK\n\nGraphEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12,\n\x05value\x18\x02 \x01(\x0b\x32\x1d.avalanche.operator.NodeEdges:\x02\x38\x01\x1a\x30\n\x0eNodeTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x33\n\x11\x44isplayNamesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x38\n\x16\x41gentMetadataJsonEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"{\n\x08\x46lowList\x12.\n\x05\x66lows\x18\x01 \x03(\x0b\x32\x1f.avalanche.operator.FlowInfoMsg\x12?\n\x0b\x64iagnostics\x18\x02 \x03(\x0b\x32*.avalanche.operator.DiscoveryDiagnosticMsg\"E\n\x16\x44iscoveryDiagnosticMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\"\x92\x01\n\x14ResultFileAttachment\x12\x15\n\rattachment_id\x18\x01 \x01(\t\x12\x11\n\x04name\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\x12\x17\n\nmedia_type\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x0e\n\x06sha256\x18\x05 \x01(\tB\x07\n\x05_nameB\r\n\x0b_media_type\"[\n\x0cRunResultMsg\x12\x12\n\nvalue_json\x18\x01 \x01(\t\x12\x37\n\x05\x66iles\x18\x02 \x03(\x0b\x32(.avalanche.operator.ResultFileAttachment\"\xde\x01\n\rRunSummaryMsg\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x11\n\tflow_name\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x12\n\nstarted_at\x18\x04 \x01(\x01\x12\x10\n\x08\x65nded_at\x18\x05 \x01(\x01\x12\x14\n\x0ctriggered_by\x18\x06 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x07 \x01(\t\x12\x1d\n\x15workflow_display_name\x18\x08 \x01(\t\x12\x18\n\x10\x63reated_sequence\x18\t \x01(\x04\x12\x10\n\x08revision\x18\n \x01(\x04\"\xa3\x01\n\x12TraceDescriptorMsg\x12\x0e\n\x06status\x18\x01 \x01(\t\x12\x10\n\x08revision\x18\x02 \x01(\x04\x12\x11\n\tavailable\x18\x03 \x01(\x08\x12\x10\n\x08\x63omplete\x18\x04 \x01(\x08\x12\x13\n\x0b\x65vent_count\x18\x05 \x01(\x04\x12\x12\n\nsize_bytes\x18\x06 \x01(\x04\x12\x1d\n\x15latest_event_sequence\x18\x07 \x01(\x04\"\xdc\x01\n\x0fNodeSnapshotMsg\x12\x0f\n\x07node_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x11\n\tnode_type\x18\x03 \x01(\t\x12\x0e\n\x06status\x18\x04 \x01(\t\x12\x12\n\nstarted_at\x18\x05 \x01(\x01\x12\x10\n\x08\x65nded_at\x18\x06 \x01(\x01\x12\x35\n\x05trace\x18\x07 \x01(\x0b\x32&.avalanche.operator.TraceDescriptorMsg\x12\x10\n\x08revision\x18\x08 \x01(\x04\x12\x18\n\x10\x65vent_page_token\x18\t \x01(\t\"\xe3\x01\n\x0eRunSnapshotMsg\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12\x32\n\x07summary\x18\x03 \x01(\x0b\x32!.avalanche.operator.RunSummaryMsg\x12\x32\n\x05nodes\x18\x04 \x03(\x0b\x32#.avalanche.operator.NodeSnapshotMsg\x12\x1b\n\x13latest_log_sequence\x18\x05 \x01(\x04\x12\x16\n\x0elog_page_token\x18\x06 \x01(\t\"\x90\x01\n\x0eRunSummaryPage\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12/\n\x04runs\x18\x03 \x03(\x0b\x32!.avalanche.operator.RunSummaryMsg\x12\x17\n\x0fnext_page_token\x18\x04 \x01(\t\"\x85\x01\n\x16LogRecordDescriptorMsg\x12\x10\n\x08sequence\x18\x01 \x01(\x04\x12\x11\n\ttimestamp\x18\x02 \x01(\x01\x12\r\n\x05level\x18\x03 \x01(\t\x12\x0f\n\x07node_id\x18\x04 \x01(\t\x12\x12\n\nsize_bytes\x18\x05 \x01(\x04\x12\x12\n\nbody_token\x18\x06 \x01(\t\"\x92\x01\n\x07LogPage\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12\x38\n\x04logs\x18\x03 \x03(\x0b\x32*.avalanche.operator.LogRecordDescriptorMsg\x12\x17\n\x0fnext_page_token\x18\x04 \x01(\t\"p\n\x17\x41gentEventDescriptorMsg\x12\x16\n\x0e\x65vent_sequence\x18\x01 \x01(\x04\x12\x12\n\nsize_bytes\x18\x02 \x01(\x04\x12\x12\n\nbody_token\x18\x03 \x01(\t\x12\x15\n\rinvocation_id\x18\x04 \x01(\t\"\xbd\x01\n\x0e\x41gentEventPage\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12\x0e\n\x06run_id\x18\x03 \x01(\t\x12\x0f\n\x07node_id\x18\x04 \x01(\t\x12;\n\x06\x65vents\x18\x05 \x03(\x0b\x32+.avalanche.operator.AgentEventDescriptorMsg\x12\x17\n\x0fnext_page_token\x18\x06 \x01(\t\"N\n\nTraceChunk\x12\x10\n\x08revision\x18\x01 \x01(\x04\x12\x13\n\x0b\x63hunk_index\x18\x02 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x0b\n\x03\x65of\x18\x04 \x01(\x08\"=\n\x0b\x44\x65tailChunk\x12\x13\n\x0b\x63hunk_index\x18\x01 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0b\n\x03\x65of\x18\x03 \x01(\x08\"t\n\nRunCreated\x12\x32\n\x07summary\x18\x01 \x01(\x0b\x32!.avalanche.operator.RunSummaryMsg\x12\x32\n\x05nodes\x18\x02 \x03(\x0b\x32#.avalanche.operator.NodeSnapshotMsg\"j\n\x10RunStatusChanged\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0e\n\x06status\x18\x02 \x01(\t\x12\x12\n\nstarted_at\x18\x03 \x01(\x01\x12\x10\n\x08\x65nded_at\x18\x04 \x01(\x01\x12\x10\n\x08revision\x18\x05 \x01(\x04\"|\n\x11NodeStatusChanged\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x12\n\nstarted_at\x18\x04 \x01(\x01\x12\x10\n\x08\x65nded_at\x18\x05 \x01(\x01\x12\x10\n\x08revision\x18\x06 \x01(\x04\"V\n\x0bLogAppended\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x37\n\x03log\x18\x02 \x01(\x0b\x32*.avalanche.operator.LogRecordDescriptorMsg\"q\n\x12\x41gentEventAppended\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12:\n\x05\x65vent\x18\x03 \x01(\x0b\x32+.avalanche.operator.AgentEventDescriptorMsg\"h\n\x0eTraceFinalized\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12\x35\n\x05trace\x18\x03 \x01(\x0b\x32&.avalanche.operator.TraceDescriptorMsg\"\xa8\x03\n\tRunUpdate\x12\x10\n\x08sequence\x18\x01 \x01(\x04\x12\x35\n\x0brun_created\x18\x02 \x01(\x0b\x32\x1e.avalanche.operator.RunCreatedH\x00\x12\x42\n\x12run_status_changed\x18\x03 \x01(\x0b\x32$.avalanche.operator.RunStatusChangedH\x00\x12\x44\n\x13node_status_changed\x18\x04 \x01(\x0b\x32%.avalanche.operator.NodeStatusChangedH\x00\x12\x37\n\x0clog_appended\x18\x05 \x01(\x0b\x32\x1f.avalanche.operator.LogAppendedH\x00\x12\x46\n\x14\x61gent_event_appended\x18\x06 \x01(\x0b\x32&.avalanche.operator.AgentEventAppendedH\x00\x12=\n\x0ftrace_finalized\x18\x07 \x01(\x0b\x32\".avalanche.operator.TraceFinalizedH\x00\x42\x08\n\x06\x63hange\"?\n\rResetRequired\x12\x15\n\rhistory_floor\x18\x01 \x01(\x04\x12\x17\n\x0flatest_sequence\x18\x02 \x01(\x04\"\xaa\x01\n\x11RunUpdateEnvelope\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12/\n\x06update\x18\x02 \x01(\x0b\x32\x1d.avalanche.operator.RunUpdateH\x00\x12;\n\x0ereset_required\x18\x03 \x01(\x0b\x32!.avalanche.operator.ResetRequiredH\x00\x42\t\n\x07payload2\xdf\x07\n\x0fOperatorService\x12\x44\n\tListFlows\x12\x19.avalanche.operator.Empty\x1a\x1c.avalanche.operator.FlowList\x12U\n\x08StartRun\x12#.avalanche.operator.StartRunRequest\x1a$.avalanche.operator.StartRunResponse\x12L\n\tCancelRun\x12$.avalanche.operator.CancelRunRequest\x1a\x19.avalanche.operator.Empty\x12S\n\x0cGetRunResult\x12!.avalanche.operator.GetRunRequest\x1a .avalanche.operator.RunResultMsg\x12\x63\n\x10ListRunSummaries\x12+.avalanche.operator.ListRunSummariesRequest\x1a\".avalanche.operator.RunSummaryPage\x12_\n\x0eGetRunSnapshot\x12).avalanche.operator.GetRunSnapshotRequest\x1a\".avalanche.operator.RunSnapshotMsg\x12L\n\x08ListLogs\x12#.avalanche.operator.ListLogsRequest\x1a\x1b.avalanche.operator.LogPage\x12\x61\n\x0fListAgentEvents\x12*.avalanche.operator.ListAgentEventsRequest\x1a\".avalanche.operator.AgentEventPage\x12S\n\tReadTrace\x12$.avalanche.operator.ReadTraceRequest\x1a\x1e.avalanche.operator.TraceChunk0\x01\x12V\n\nReadDetail\x12%.avalanche.operator.ReadDetailRequest\x1a\x1f.avalanche.operator.DetailChunk0\x01\x12h\n\x10StreamRunUpdates\x12+.avalanche.operator.StreamRunUpdatesRequest\x1a%.avalanche.operator.RunUpdateEnvelope0\x01\x62\x06proto3') +DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\x0eoperator.proto\x12\x12\x61valanche.operator\"\x07\n\x05\x45mpty\"\xa5\x01\n\x0fStartRunRequest\x12\x12\n\ninput_json\x18\x02 \x01(\t\x12\x14\n\x0c\x63ontext_json\x18\x03 \x01(\t\x12\x37\n\x0binput_files\x18\x04 \x03(\x0b\x32\".avalanche.operator.FileAttachment\x12\x0e\n\x06run_id\x18\x06 \x01(\t\x12\x19\n\x11workflow_selector\x18\x07 \x01(\tJ\x04\x08\x01\x10\x02\"i\n\x0e\x46ileAttachment\x12\x12\n\nfield_name\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\x12\x14\n\x0c\x63ontent_type\x18\x04 \x01(\t\x12\x0e\n\x06sha256\x18\x05 \x01(\t\"\"\n\x10StartRunResponse\x12\x0e\n\x06run_id\x18\x01 \x01(\t\"\"\n\x10\x43\x61ncelRunRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\"\x1f\n\rGetRunRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\"[\n\x17ListRunSummariesRequest\x12\x19\n\x11workflow_selector\x18\x01 \x01(\t\x12\x11\n\tpage_size\x18\x02 \x01(\r\x12\x12\n\npage_token\x18\x03 \x01(\t\"]\n\x15GetRunSnapshotRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x1c\n\x14operator_instance_id\x18\x02 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x03 \x01(\x04\"K\n\x1bGetLatestRunSnapshotRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x1c\n\x14operator_instance_id\x18\x02 \x01(\t\"\xb2\x01\n\x0fListLogsRequest\x12\x12\n\npage_token\x18\x01 \x01(\t\x12\x16\n\x0e\x61\x66ter_sequence\x18\x02 \x01(\x04\x12\x11\n\tpage_size\x18\x03 \x01(\r\x12\x17\n\x0f\x62\x65\x66ore_sequence\x18\x04 \x01(\x04\x12\x0f\n\x07node_id\x18\x05 \x01(\t\x12\x36\n\x05order\x18\x06 \x01(\x0e\x32\'.avalanche.operator.DescriptorPageOrder\"\xb4\x01\n\x16ListAgentEventsRequest\x12\x12\n\npage_token\x18\x01 \x01(\t\x12\x1c\n\x14\x61\x66ter_event_sequence\x18\x02 \x01(\x04\x12\x11\n\tpage_size\x18\x03 \x01(\r\x12\x1d\n\x15\x62\x65\x66ore_event_sequence\x18\x04 \x01(\x04\x12\x36\n\x05order\x18\x05 \x01(\x0e\x32\'.avalanche.operator.DescriptorPageOrder\"c\n\x10ReadTraceRequest\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12\x10\n\x08revision\x18\x03 \x01(\x04\x12\x1c\n\x14operator_instance_id\x18\x04 \x01(\t\"\'\n\x11ReadDetailRequest\x12\x12\n\nbody_token\x18\x01 \x01(\t\"T\n\x1cStreamOperatorUpdatesRequest\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61\x66ter_sequence\x18\x02 \x01(\x04\"\x1d\n\tNodeEdges\x12\x10\n\x08\x63hildren\x18\x01 \x03(\t\"\x83\x06\n\x13WorkflowTopologyMsg\x12\x10\n\x08node_ids\x18\x01 \x03(\t\x12\x41\n\x05graph\x18\x02 \x03(\x0b\x32\x32.avalanche.operator.WorkflowTopologyMsg.GraphEntry\x12J\n\nnode_types\x18\x03 \x03(\x0b\x32\x36.avalanche.operator.WorkflowTopologyMsg.NodeTypesEntry\x12P\n\rdisplay_names\x18\x04 \x03(\x0b\x32\x39.avalanche.operator.WorkflowTopologyMsg.DisplayNamesEntry\x12\x64\n\x18\x61gent_field_schemas_json\x18\x05 \x03(\x0b\x32\x42.avalanche.operator.WorkflowTopologyMsg.AgentFieldSchemasJsonEntry\x12\x63\n\x17\x61gent_instruction_lines\x18\x06 \x03(\x0b\x32\x42.avalanche.operator.WorkflowTopologyMsg.AgentInstructionLinesEntry\x1aK\n\nGraphEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12,\n\x05value\x18\x02 \x01(\x0b\x32\x1d.avalanche.operator.NodeEdges:\x02\x38\x01\x1a\x30\n\x0eNodeTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x33\n\x11\x44isplayNamesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a<\n\x1a\x41gentFieldSchemasJsonEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a<\n\x1a\x41gentInstructionLinesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"\xcd\x06\n\x0b\x46lowInfoMsg\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x11\n\tfile_path\x18\x02 \x01(\t\x12\x10\n\x08node_ids\x18\x03 \x03(\t\x12\x39\n\x05graph\x18\x04 \x03(\x0b\x32*.avalanche.operator.FlowInfoMsg.GraphEntry\x12\x42\n\nnode_types\x18\x05 \x03(\x0b\x32..avalanche.operator.FlowInfoMsg.NodeTypesEntry\x12H\n\rdisplay_names\x18\x06 \x03(\x0b\x32\x31.avalanche.operator.FlowInfoMsg.DisplayNamesEntry\x12\x0c\n\x04\x63ron\x18\x07 \x01(\t\x12\x13\n\x0bnext_run_at\x18\x08 \x01(\x01\x12\x13\n\x0blast_run_at\x18\t \x01(\x01\x12\x13\n\x0bworkflow_id\x18\n \x01(\t\x12\x14\n\x0c\x64isplay_name\x18\x0b \x01(\t\x12\x12\n\nroot_alias\x18\x0c \x01(\t\x12\x15\n\rrelative_file\x18\r \x01(\t\x12\x16\n\x0e\x62uilder_symbol\x18\x0e \x01(\t\x12\x16\n\x0e\x61gent_node_ids\x18\x0f \x03(\t\x12S\n\x13\x61gent_metadata_json\x18\x10 \x03(\x0b\x32\x36.avalanche.operator.FlowInfoMsg.AgentMetadataJsonEntry\x12\x14\n\x0cwebhook_path\x18\x11 \x01(\t\x12\x13\n\x0bwebhook_url\x18\x12 \x01(\t\x12\x16\n\x0ewebhook_active\x18\x13 \x01(\x08\x1aK\n\nGraphEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12,\n\x05value\x18\x02 \x01(\x0b\x32\x1d.avalanche.operator.NodeEdges:\x02\x38\x01\x1a\x30\n\x0eNodeTypesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x33\n\x11\x44isplayNamesEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\x1a\x38\n\x16\x41gentMetadataJsonEntry\x12\x0b\n\x03key\x18\x01 \x01(\t\x12\r\n\x05value\x18\x02 \x01(\t:\x02\x38\x01\"E\n\x16\x44iscoveryDiagnosticMsg\x12\x0c\n\x04path\x18\x01 \x01(\t\x12\x0c\n\x04kind\x18\x02 \x01(\t\x12\x0f\n\x07message\x18\x03 \x01(\t\"A\n\rScanTargetMsg\x12\r\n\x05\x61lias\x18\x01 \x01(\t\x12\x13\n\x0btarget_path\x18\x02 \x01(\t\x12\x0c\n\x04kind\x18\x03 \x01(\t\"\x8a\x02\n\x12\x43\x61talogSnapshotMsg\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12\x10\n\x08revision\x18\x03 \x01(\x04\x12\x32\n\tworkflows\x18\x04 \x03(\x0b\x32\x1f.avalanche.operator.FlowInfoMsg\x12\x37\n\x0cscan_targets\x18\x05 \x03(\x0b\x32!.avalanche.operator.ScanTargetMsg\x12?\n\x0b\x64iagnostics\x18\x06 \x03(\x0b\x32*.avalanche.operator.DiscoveryDiagnosticMsg\"\x92\x01\n\x14ResultFileAttachment\x12\x15\n\rattachment_id\x18\x01 \x01(\t\x12\x11\n\x04name\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x0f\n\x07\x63ontent\x18\x03 \x01(\x0c\x12\x17\n\nmedia_type\x18\x04 \x01(\tH\x01\x88\x01\x01\x12\x0e\n\x06sha256\x18\x05 \x01(\tB\x07\n\x05_nameB\r\n\x0b_media_type\"[\n\x0cRunResultMsg\x12\x12\n\nvalue_json\x18\x01 \x01(\t\x12\x37\n\x05\x66iles\x18\x02 \x03(\x0b\x32(.avalanche.operator.ResultFileAttachment\"\xf4\x01\n\rRunSummaryMsg\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x11\n\tflow_name\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x12\n\nstarted_at\x18\x04 \x01(\x01\x12\x10\n\x08\x65nded_at\x18\x05 \x01(\x01\x12\x14\n\x0ctriggered_by\x18\x06 \x01(\t\x12\x13\n\x0bworkflow_id\x18\x07 \x01(\t\x12\x1d\n\x15workflow_display_name\x18\x08 \x01(\t\x12\x18\n\x10\x63reated_sequence\x18\t \x01(\x04\x12\x10\n\x08revision\x18\n \x01(\x04\x12\x14\n\x0ctriggered_at\x18\x0b \x01(\x01\"\xda\x01\n\x0eTraceHeaderMsg\x12\x0e\n\x06status\x18\x01 \x01(\t\x12\r\n\x05model\x18\x02 \x01(\t\x12\x16\n\tsub_model\x18\x03 \x01(\tH\x00\x88\x01\x01\x12\x12\n\niterations\x18\x04 \x01(\x04\x12\x16\n\x0emax_iterations\x18\x05 \x01(\x04\x12\x13\n\x0b\x64uration_ms\x18\x06 \x01(\x04\x12\x12\n\nusage_json\x18\x07 \x01(\t\x12\x1b\n\x0etelemetry_json\x18\x08 \x01(\tH\x01\x88\x01\x01\x42\x0c\n\n_sub_modelB\x11\n\x0f_telemetry_json\"\xd7\x01\n\x12TraceDescriptorMsg\x12\x0e\n\x06status\x18\x01 \x01(\t\x12\x10\n\x08revision\x18\x02 \x01(\x04\x12\x11\n\tavailable\x18\x03 \x01(\x08\x12\x10\n\x08\x63omplete\x18\x04 \x01(\x08\x12\x13\n\x0b\x65vent_count\x18\x05 \x01(\x04\x12\x12\n\nsize_bytes\x18\x06 \x01(\x04\x12\x1d\n\x15latest_event_sequence\x18\x07 \x01(\x04\x12\x32\n\x06header\x18\x08 \x01(\x0b\x32\".avalanche.operator.TraceHeaderMsg\"\xbc\x02\n\x0fNodeSnapshotMsg\x12\x0f\n\x07node_id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x11\n\tnode_type\x18\x03 \x01(\t\x12\x0e\n\x06status\x18\x04 \x01(\t\x12\x12\n\nstarted_at\x18\x05 \x01(\x01\x12\x10\n\x08\x65nded_at\x18\x06 \x01(\x01\x12\x35\n\x05trace\x18\x07 \x01(\x0b\x32&.avalanche.operator.TraceDescriptorMsg\x12\x10\n\x08revision\x18\x08 \x01(\x04\x12\x18\n\x10\x65vent_page_token\x18\t \x01(\t\x12\x12\n\x05\x65rror\x18\n \x01(\tH\x00\x88\x01\x01\x12$\n\x17running_elapsed_seconds\x18\x0b \x01(\x01H\x01\x88\x01\x01\x42\x08\n\x06_errorB\x1a\n\x18_running_elapsed_seconds\"\x9e\x02\n\x0eRunSnapshotMsg\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12\x32\n\x07summary\x18\x03 \x01(\x0b\x32!.avalanche.operator.RunSummaryMsg\x12\x32\n\x05nodes\x18\x04 \x03(\x0b\x32#.avalanche.operator.NodeSnapshotMsg\x12\x1b\n\x13latest_log_sequence\x18\x05 \x01(\x04\x12\x16\n\x0elog_page_token\x18\x06 \x01(\t\x12\x39\n\x08topology\x18\x07 \x01(\x0b\x32\'.avalanche.operator.WorkflowTopologyMsg\"\x90\x01\n\x0eRunSummaryPage\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12/\n\x04runs\x18\x03 \x03(\x0b\x32!.avalanche.operator.RunSummaryMsg\x12\x17\n\x0fnext_page_token\x18\x04 \x01(\t\"\x85\x01\n\x16LogRecordDescriptorMsg\x12\x10\n\x08sequence\x18\x01 \x01(\x04\x12\x11\n\ttimestamp\x18\x02 \x01(\x01\x12\r\n\x05level\x18\x03 \x01(\t\x12\x0f\n\x07node_id\x18\x04 \x01(\t\x12\x12\n\nsize_bytes\x18\x05 \x01(\x04\x12\x12\n\nbody_token\x18\x06 \x01(\t\"\x92\x01\n\x07LogPage\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12\x38\n\x04logs\x18\x03 \x03(\x0b\x32*.avalanche.operator.LogRecordDescriptorMsg\x12\x17\n\x0fnext_page_token\x18\x04 \x01(\t\"\x8e\x02\n\x17\x41gentEventDescriptorMsg\x12\x16\n\x0e\x65vent_sequence\x18\x01 \x01(\x04\x12\x12\n\nsize_bytes\x18\x02 \x01(\x04\x12\x12\n\nbody_token\x18\x03 \x01(\t\x12\x15\n\rinvocation_id\x18\x04 \x01(\t\x12\x12\n\nevent_kind\x18\x05 \x01(\t\x12\x16\n\titeration\x18\x06 \x01(\rH\x00\x88\x01\x01\x12\x18\n\x0b\x64uration_ms\x18\x07 \x01(\x04H\x01\x88\x01\x01\x12\r\n\x05\x65rror\x18\x08 \x01(\x08\x12\x12\n\ntool_count\x18\t \x01(\r\x12\x15\n\rpredict_count\x18\n \x01(\rB\x0c\n\n_iterationB\x0e\n\x0c_duration_ms\"\xbd\x01\n\x0e\x41gentEventPage\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x16\n\x0e\x61s_of_sequence\x18\x02 \x01(\x04\x12\x0e\n\x06run_id\x18\x03 \x01(\t\x12\x0f\n\x07node_id\x18\x04 \x01(\t\x12;\n\x06\x65vents\x18\x05 \x03(\x0b\x32+.avalanche.operator.AgentEventDescriptorMsg\x12\x17\n\x0fnext_page_token\x18\x06 \x01(\t\"N\n\nTraceChunk\x12\x10\n\x08revision\x18\x01 \x01(\x04\x12\x13\n\x0b\x63hunk_index\x18\x02 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x03 \x01(\x0c\x12\x0b\n\x03\x65of\x18\x04 \x01(\x08\"=\n\x0b\x44\x65tailChunk\x12\x13\n\x0b\x63hunk_index\x18\x01 \x01(\x04\x12\x0c\n\x04\x64\x61ta\x18\x02 \x01(\x0c\x12\x0b\n\x03\x65of\x18\x03 \x01(\x08\"\xaf\x01\n\nRunCreated\x12\x32\n\x07summary\x18\x01 \x01(\x0b\x32!.avalanche.operator.RunSummaryMsg\x12\x32\n\x05nodes\x18\x02 \x03(\x0b\x32#.avalanche.operator.NodeSnapshotMsg\x12\x39\n\x08topology\x18\x03 \x01(\x0b\x32\'.avalanche.operator.WorkflowTopologyMsg\"j\n\x10RunStatusChanged\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0e\n\x06status\x18\x02 \x01(\t\x12\x12\n\nstarted_at\x18\x03 \x01(\x01\x12\x10\n\x08\x65nded_at\x18\x04 \x01(\x01\x12\x10\n\x08revision\x18\x05 \x01(\x04\"\xdc\x01\n\x11NodeStatusChanged\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12\x0e\n\x06status\x18\x03 \x01(\t\x12\x12\n\nstarted_at\x18\x04 \x01(\x01\x12\x10\n\x08\x65nded_at\x18\x05 \x01(\x01\x12\x10\n\x08revision\x18\x06 \x01(\x04\x12\x12\n\x05\x65rror\x18\x07 \x01(\tH\x00\x88\x01\x01\x12$\n\x17running_elapsed_seconds\x18\x08 \x01(\x01H\x01\x88\x01\x01\x42\x08\n\x06_errorB\x1a\n\x18_running_elapsed_seconds\"V\n\x0bLogAppended\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x37\n\x03log\x18\x02 \x01(\x0b\x32*.avalanche.operator.LogRecordDescriptorMsg\"q\n\x12\x41gentEventAppended\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12:\n\x05\x65vent\x18\x03 \x01(\x0b\x32+.avalanche.operator.AgentEventDescriptorMsg\"h\n\x0eTraceFinalized\x12\x0e\n\x06run_id\x18\x01 \x01(\t\x12\x0f\n\x07node_id\x18\x02 \x01(\t\x12\x35\n\x05trace\x18\x03 \x01(\x0b\x32&.avalanche.operator.TraceDescriptorMsg\"J\n\x0f\x43\x61talogReplaced\x12\x37\n\x07\x63\x61talog\x18\x01 \x01(\x0b\x32&.avalanche.operator.CatalogSnapshotMsg\"\xee\x03\n\x0eOperatorUpdate\x12\x10\n\x08sequence\x18\x01 \x01(\x04\x12\x35\n\x0brun_created\x18\x02 \x01(\x0b\x32\x1e.avalanche.operator.RunCreatedH\x00\x12\x42\n\x12run_status_changed\x18\x03 \x01(\x0b\x32$.avalanche.operator.RunStatusChangedH\x00\x12\x44\n\x13node_status_changed\x18\x04 \x01(\x0b\x32%.avalanche.operator.NodeStatusChangedH\x00\x12\x37\n\x0clog_appended\x18\x05 \x01(\x0b\x32\x1f.avalanche.operator.LogAppendedH\x00\x12\x46\n\x14\x61gent_event_appended\x18\x06 \x01(\x0b\x32&.avalanche.operator.AgentEventAppendedH\x00\x12=\n\x0ftrace_finalized\x18\x07 \x01(\x0b\x32\".avalanche.operator.TraceFinalizedH\x00\x12?\n\x10\x63\x61talog_replaced\x18\x08 \x01(\x0b\x32#.avalanche.operator.CatalogReplacedH\x00\x42\x08\n\x06\x63hange\"?\n\rResetRequired\x12\x15\n\rhistory_floor\x18\x01 \x01(\x04\x12\x17\n\x0flatest_sequence\x18\x02 \x01(\x04\"\xb4\x01\n\x16OperatorUpdateEnvelope\x12\x1c\n\x14operator_instance_id\x18\x01 \x01(\t\x12\x34\n\x06update\x18\x02 \x01(\x0b\x32\".avalanche.operator.OperatorUpdateH\x00\x12;\n\x0ereset_required\x18\x03 \x01(\x0b\x32!.avalanche.operator.ResetRequiredH\x00\x42\t\n\x07payload*`\n\x13\x44\x65scriptorPageOrder\x12!\n\x1d\x44\x45SCRIPTOR_PAGE_ORDER_FORWARD\x10\x00\x12&\n\"DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST\x10\x01\x32\xe6\x08\n\x0fOperatorService\x12O\n\nGetCatalog\x12\x19.avalanche.operator.Empty\x1a&.avalanche.operator.CatalogSnapshotMsg\x12U\n\x08StartRun\x12#.avalanche.operator.StartRunRequest\x1a$.avalanche.operator.StartRunResponse\x12L\n\tCancelRun\x12$.avalanche.operator.CancelRunRequest\x1a\x19.avalanche.operator.Empty\x12S\n\x0cGetRunResult\x12!.avalanche.operator.GetRunRequest\x1a .avalanche.operator.RunResultMsg\x12\x63\n\x10ListRunSummaries\x12+.avalanche.operator.ListRunSummariesRequest\x1a\".avalanche.operator.RunSummaryPage\x12_\n\x0eGetRunSnapshot\x12).avalanche.operator.GetRunSnapshotRequest\x1a\".avalanche.operator.RunSnapshotMsg\x12k\n\x14GetLatestRunSnapshot\x12/.avalanche.operator.GetLatestRunSnapshotRequest\x1a\".avalanche.operator.RunSnapshotMsg\x12L\n\x08ListLogs\x12#.avalanche.operator.ListLogsRequest\x1a\x1b.avalanche.operator.LogPage\x12\x61\n\x0fListAgentEvents\x12*.avalanche.operator.ListAgentEventsRequest\x1a\".avalanche.operator.AgentEventPage\x12S\n\tReadTrace\x12$.avalanche.operator.ReadTraceRequest\x1a\x1e.avalanche.operator.TraceChunk0\x01\x12V\n\nReadDetail\x12%.avalanche.operator.ReadDetailRequest\x1a\x1f.avalanche.operator.DetailChunk0\x01\x12w\n\x15StreamOperatorUpdates\x12\x30.avalanche.operator.StreamOperatorUpdatesRequest\x1a*.avalanche.operator.OperatorUpdateEnvelope0\x01\x62\x06proto3') _globals = globals() _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals) _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'operator_pb2', _globals) if not _descriptor._USE_C_DESCRIPTORS: DESCRIPTOR._loaded_options = None + _globals['_WORKFLOWTOPOLOGYMSG_GRAPHENTRY']._loaded_options = None + _globals['_WORKFLOWTOPOLOGYMSG_GRAPHENTRY']._serialized_options = b'8\001' + _globals['_WORKFLOWTOPOLOGYMSG_NODETYPESENTRY']._loaded_options = None + _globals['_WORKFLOWTOPOLOGYMSG_NODETYPESENTRY']._serialized_options = b'8\001' + _globals['_WORKFLOWTOPOLOGYMSG_DISPLAYNAMESENTRY']._loaded_options = None + _globals['_WORKFLOWTOPOLOGYMSG_DISPLAYNAMESENTRY']._serialized_options = b'8\001' + _globals['_WORKFLOWTOPOLOGYMSG_AGENTFIELDSCHEMASJSONENTRY']._loaded_options = None + _globals['_WORKFLOWTOPOLOGYMSG_AGENTFIELDSCHEMASJSONENTRY']._serialized_options = b'8\001' + _globals['_WORKFLOWTOPOLOGYMSG_AGENTINSTRUCTIONLINESENTRY']._loaded_options = None + _globals['_WORKFLOWTOPOLOGYMSG_AGENTINSTRUCTIONLINESENTRY']._serialized_options = b'8\001' _globals['_FLOWINFOMSG_GRAPHENTRY']._loaded_options = None _globals['_FLOWINFOMSG_GRAPHENTRY']._serialized_options = b'8\001' _globals['_FLOWINFOMSG_NODETYPESENTRY']._loaded_options = None @@ -39,92 +49,114 @@ _globals['_FLOWINFOMSG_DISPLAYNAMESENTRY']._serialized_options = b'8\001' _globals['_FLOWINFOMSG_AGENTMETADATAJSONENTRY']._loaded_options = None _globals['_FLOWINFOMSG_AGENTMETADATAJSONENTRY']._serialized_options = b'8\001' + _globals['_DESCRIPTORPAGEORDER']._serialized_start=7559 + _globals['_DESCRIPTORPAGEORDER']._serialized_end=7655 _globals['_EMPTY']._serialized_start=38 _globals['_EMPTY']._serialized_end=45 _globals['_STARTRUNREQUEST']._serialized_start=48 - _globals['_STARTRUNREQUEST']._serialized_end=226 - _globals['_FILEATTACHMENT']._serialized_start=228 - _globals['_FILEATTACHMENT']._serialized_end=333 - _globals['_STARTRUNRESPONSE']._serialized_start=335 - _globals['_STARTRUNRESPONSE']._serialized_end=369 - _globals['_CANCELRUNREQUEST']._serialized_start=371 - _globals['_CANCELRUNREQUEST']._serialized_end=405 - _globals['_GETRUNREQUEST']._serialized_start=407 - _globals['_GETRUNREQUEST']._serialized_end=438 - _globals['_LISTRUNSUMMARIESREQUEST']._serialized_start=440 - _globals['_LISTRUNSUMMARIESREQUEST']._serialized_end=531 - _globals['_GETRUNSNAPSHOTREQUEST']._serialized_start=533 - _globals['_GETRUNSNAPSHOTREQUEST']._serialized_end=626 - _globals['_LISTLOGSREQUEST']._serialized_start=628 - _globals['_LISTLOGSREQUEST']._serialized_end=708 - _globals['_LISTAGENTEVENTSREQUEST']._serialized_start=710 - _globals['_LISTAGENTEVENTSREQUEST']._serialized_end=803 - _globals['_READTRACEREQUEST']._serialized_start=805 - _globals['_READTRACEREQUEST']._serialized_end=904 - _globals['_READDETAILREQUEST']._serialized_start=906 - _globals['_READDETAILREQUEST']._serialized_end=945 - _globals['_STREAMRUNUPDATESREQUEST']._serialized_start=947 - _globals['_STREAMRUNUPDATESREQUEST']._serialized_end=1026 - _globals['_NODEEDGES']._serialized_start=1028 - _globals['_NODEEDGES']._serialized_end=1057 - _globals['_FLOWINFOMSG']._serialized_start=1060 - _globals['_FLOWINFOMSG']._serialized_end=1905 - _globals['_FLOWINFOMSG_GRAPHENTRY']._serialized_start=1669 - _globals['_FLOWINFOMSG_GRAPHENTRY']._serialized_end=1744 - _globals['_FLOWINFOMSG_NODETYPESENTRY']._serialized_start=1746 - _globals['_FLOWINFOMSG_NODETYPESENTRY']._serialized_end=1794 - _globals['_FLOWINFOMSG_DISPLAYNAMESENTRY']._serialized_start=1796 - _globals['_FLOWINFOMSG_DISPLAYNAMESENTRY']._serialized_end=1847 - _globals['_FLOWINFOMSG_AGENTMETADATAJSONENTRY']._serialized_start=1849 - _globals['_FLOWINFOMSG_AGENTMETADATAJSONENTRY']._serialized_end=1905 - _globals['_FLOWLIST']._serialized_start=1907 - _globals['_FLOWLIST']._serialized_end=2030 - _globals['_DISCOVERYDIAGNOSTICMSG']._serialized_start=2032 - _globals['_DISCOVERYDIAGNOSTICMSG']._serialized_end=2101 - _globals['_RESULTFILEATTACHMENT']._serialized_start=2104 - _globals['_RESULTFILEATTACHMENT']._serialized_end=2250 - _globals['_RUNRESULTMSG']._serialized_start=2252 - _globals['_RUNRESULTMSG']._serialized_end=2343 - _globals['_RUNSUMMARYMSG']._serialized_start=2346 - _globals['_RUNSUMMARYMSG']._serialized_end=2568 - _globals['_TRACEDESCRIPTORMSG']._serialized_start=2571 - _globals['_TRACEDESCRIPTORMSG']._serialized_end=2734 - _globals['_NODESNAPSHOTMSG']._serialized_start=2737 - _globals['_NODESNAPSHOTMSG']._serialized_end=2957 - _globals['_RUNSNAPSHOTMSG']._serialized_start=2960 - _globals['_RUNSNAPSHOTMSG']._serialized_end=3187 - _globals['_RUNSUMMARYPAGE']._serialized_start=3190 - _globals['_RUNSUMMARYPAGE']._serialized_end=3334 - _globals['_LOGRECORDDESCRIPTORMSG']._serialized_start=3337 - _globals['_LOGRECORDDESCRIPTORMSG']._serialized_end=3470 - _globals['_LOGPAGE']._serialized_start=3473 - _globals['_LOGPAGE']._serialized_end=3619 - _globals['_AGENTEVENTDESCRIPTORMSG']._serialized_start=3621 - _globals['_AGENTEVENTDESCRIPTORMSG']._serialized_end=3733 - _globals['_AGENTEVENTPAGE']._serialized_start=3736 - _globals['_AGENTEVENTPAGE']._serialized_end=3925 - _globals['_TRACECHUNK']._serialized_start=3927 - _globals['_TRACECHUNK']._serialized_end=4005 - _globals['_DETAILCHUNK']._serialized_start=4007 - _globals['_DETAILCHUNK']._serialized_end=4068 - _globals['_RUNCREATED']._serialized_start=4070 - _globals['_RUNCREATED']._serialized_end=4186 - _globals['_RUNSTATUSCHANGED']._serialized_start=4188 - _globals['_RUNSTATUSCHANGED']._serialized_end=4294 - _globals['_NODESTATUSCHANGED']._serialized_start=4296 - _globals['_NODESTATUSCHANGED']._serialized_end=4420 - _globals['_LOGAPPENDED']._serialized_start=4422 - _globals['_LOGAPPENDED']._serialized_end=4508 - _globals['_AGENTEVENTAPPENDED']._serialized_start=4510 - _globals['_AGENTEVENTAPPENDED']._serialized_end=4623 - _globals['_TRACEFINALIZED']._serialized_start=4625 - _globals['_TRACEFINALIZED']._serialized_end=4729 - _globals['_RUNUPDATE']._serialized_start=4732 - _globals['_RUNUPDATE']._serialized_end=5156 - _globals['_RESETREQUIRED']._serialized_start=5158 - _globals['_RESETREQUIRED']._serialized_end=5221 - _globals['_RUNUPDATEENVELOPE']._serialized_start=5224 - _globals['_RUNUPDATEENVELOPE']._serialized_end=5394 - _globals['_OPERATORSERVICE']._serialized_start=5397 - _globals['_OPERATORSERVICE']._serialized_end=6388 + _globals['_STARTRUNREQUEST']._serialized_end=213 + _globals['_FILEATTACHMENT']._serialized_start=215 + _globals['_FILEATTACHMENT']._serialized_end=320 + _globals['_STARTRUNRESPONSE']._serialized_start=322 + _globals['_STARTRUNRESPONSE']._serialized_end=356 + _globals['_CANCELRUNREQUEST']._serialized_start=358 + _globals['_CANCELRUNREQUEST']._serialized_end=392 + _globals['_GETRUNREQUEST']._serialized_start=394 + _globals['_GETRUNREQUEST']._serialized_end=425 + _globals['_LISTRUNSUMMARIESREQUEST']._serialized_start=427 + _globals['_LISTRUNSUMMARIESREQUEST']._serialized_end=518 + _globals['_GETRUNSNAPSHOTREQUEST']._serialized_start=520 + _globals['_GETRUNSNAPSHOTREQUEST']._serialized_end=613 + _globals['_GETLATESTRUNSNAPSHOTREQUEST']._serialized_start=615 + _globals['_GETLATESTRUNSNAPSHOTREQUEST']._serialized_end=690 + _globals['_LISTLOGSREQUEST']._serialized_start=693 + _globals['_LISTLOGSREQUEST']._serialized_end=871 + _globals['_LISTAGENTEVENTSREQUEST']._serialized_start=874 + _globals['_LISTAGENTEVENTSREQUEST']._serialized_end=1054 + _globals['_READTRACEREQUEST']._serialized_start=1056 + _globals['_READTRACEREQUEST']._serialized_end=1155 + _globals['_READDETAILREQUEST']._serialized_start=1157 + _globals['_READDETAILREQUEST']._serialized_end=1196 + _globals['_STREAMOPERATORUPDATESREQUEST']._serialized_start=1198 + _globals['_STREAMOPERATORUPDATESREQUEST']._serialized_end=1282 + _globals['_NODEEDGES']._serialized_start=1284 + _globals['_NODEEDGES']._serialized_end=1313 + _globals['_WORKFLOWTOPOLOGYMSG']._serialized_start=1316 + _globals['_WORKFLOWTOPOLOGYMSG']._serialized_end=2087 + _globals['_WORKFLOWTOPOLOGYMSG_GRAPHENTRY']._serialized_start=1785 + _globals['_WORKFLOWTOPOLOGYMSG_GRAPHENTRY']._serialized_end=1860 + _globals['_WORKFLOWTOPOLOGYMSG_NODETYPESENTRY']._serialized_start=1862 + _globals['_WORKFLOWTOPOLOGYMSG_NODETYPESENTRY']._serialized_end=1910 + _globals['_WORKFLOWTOPOLOGYMSG_DISPLAYNAMESENTRY']._serialized_start=1912 + _globals['_WORKFLOWTOPOLOGYMSG_DISPLAYNAMESENTRY']._serialized_end=1963 + _globals['_WORKFLOWTOPOLOGYMSG_AGENTFIELDSCHEMASJSONENTRY']._serialized_start=1965 + _globals['_WORKFLOWTOPOLOGYMSG_AGENTFIELDSCHEMASJSONENTRY']._serialized_end=2025 + _globals['_WORKFLOWTOPOLOGYMSG_AGENTINSTRUCTIONLINESENTRY']._serialized_start=2027 + _globals['_WORKFLOWTOPOLOGYMSG_AGENTINSTRUCTIONLINESENTRY']._serialized_end=2087 + _globals['_FLOWINFOMSG']._serialized_start=2090 + _globals['_FLOWINFOMSG']._serialized_end=2935 + _globals['_FLOWINFOMSG_GRAPHENTRY']._serialized_start=1785 + _globals['_FLOWINFOMSG_GRAPHENTRY']._serialized_end=1860 + _globals['_FLOWINFOMSG_NODETYPESENTRY']._serialized_start=1862 + _globals['_FLOWINFOMSG_NODETYPESENTRY']._serialized_end=1910 + _globals['_FLOWINFOMSG_DISPLAYNAMESENTRY']._serialized_start=1912 + _globals['_FLOWINFOMSG_DISPLAYNAMESENTRY']._serialized_end=1963 + _globals['_FLOWINFOMSG_AGENTMETADATAJSONENTRY']._serialized_start=2879 + _globals['_FLOWINFOMSG_AGENTMETADATAJSONENTRY']._serialized_end=2935 + _globals['_DISCOVERYDIAGNOSTICMSG']._serialized_start=2937 + _globals['_DISCOVERYDIAGNOSTICMSG']._serialized_end=3006 + _globals['_SCANTARGETMSG']._serialized_start=3008 + _globals['_SCANTARGETMSG']._serialized_end=3073 + _globals['_CATALOGSNAPSHOTMSG']._serialized_start=3076 + _globals['_CATALOGSNAPSHOTMSG']._serialized_end=3342 + _globals['_RESULTFILEATTACHMENT']._serialized_start=3345 + _globals['_RESULTFILEATTACHMENT']._serialized_end=3491 + _globals['_RUNRESULTMSG']._serialized_start=3493 + _globals['_RUNRESULTMSG']._serialized_end=3584 + _globals['_RUNSUMMARYMSG']._serialized_start=3587 + _globals['_RUNSUMMARYMSG']._serialized_end=3831 + _globals['_TRACEHEADERMSG']._serialized_start=3834 + _globals['_TRACEHEADERMSG']._serialized_end=4052 + _globals['_TRACEDESCRIPTORMSG']._serialized_start=4055 + _globals['_TRACEDESCRIPTORMSG']._serialized_end=4270 + _globals['_NODESNAPSHOTMSG']._serialized_start=4273 + _globals['_NODESNAPSHOTMSG']._serialized_end=4589 + _globals['_RUNSNAPSHOTMSG']._serialized_start=4592 + _globals['_RUNSNAPSHOTMSG']._serialized_end=4878 + _globals['_RUNSUMMARYPAGE']._serialized_start=4881 + _globals['_RUNSUMMARYPAGE']._serialized_end=5025 + _globals['_LOGRECORDDESCRIPTORMSG']._serialized_start=5028 + _globals['_LOGRECORDDESCRIPTORMSG']._serialized_end=5161 + _globals['_LOGPAGE']._serialized_start=5164 + _globals['_LOGPAGE']._serialized_end=5310 + _globals['_AGENTEVENTDESCRIPTORMSG']._serialized_start=5313 + _globals['_AGENTEVENTDESCRIPTORMSG']._serialized_end=5583 + _globals['_AGENTEVENTPAGE']._serialized_start=5586 + _globals['_AGENTEVENTPAGE']._serialized_end=5775 + _globals['_TRACECHUNK']._serialized_start=5777 + _globals['_TRACECHUNK']._serialized_end=5855 + _globals['_DETAILCHUNK']._serialized_start=5857 + _globals['_DETAILCHUNK']._serialized_end=5918 + _globals['_RUNCREATED']._serialized_start=5921 + _globals['_RUNCREATED']._serialized_end=6096 + _globals['_RUNSTATUSCHANGED']._serialized_start=6098 + _globals['_RUNSTATUSCHANGED']._serialized_end=6204 + _globals['_NODESTATUSCHANGED']._serialized_start=6207 + _globals['_NODESTATUSCHANGED']._serialized_end=6427 + _globals['_LOGAPPENDED']._serialized_start=6429 + _globals['_LOGAPPENDED']._serialized_end=6515 + _globals['_AGENTEVENTAPPENDED']._serialized_start=6517 + _globals['_AGENTEVENTAPPENDED']._serialized_end=6630 + _globals['_TRACEFINALIZED']._serialized_start=6632 + _globals['_TRACEFINALIZED']._serialized_end=6736 + _globals['_CATALOGREPLACED']._serialized_start=6738 + _globals['_CATALOGREPLACED']._serialized_end=6812 + _globals['_OPERATORUPDATE']._serialized_start=6815 + _globals['_OPERATORUPDATE']._serialized_end=7309 + _globals['_RESETREQUIRED']._serialized_start=7311 + _globals['_RESETREQUIRED']._serialized_end=7374 + _globals['_OPERATORUPDATEENVELOPE']._serialized_start=7377 + _globals['_OPERATORUPDATEENVELOPE']._serialized_end=7557 + _globals['_OPERATORSERVICE']._serialized_start=7658 + _globals['_OPERATORSERVICE']._serialized_end=8784 # @@protoc_insertion_point(module_scope) diff --git a/src/runtime/operator/proto/operator_pb2.pyi b/src/runtime/operator/proto/operator_pb2.pyi index 52a0c84..ea17e42 100644 --- a/src/runtime/operator/proto/operator_pb2.pyi +++ b/src/runtime/operator/proto/operator_pb2.pyi @@ -1,4 +1,5 @@ from google.protobuf.internal import containers as _containers +from google.protobuf.internal import enum_type_wrapper as _enum_type_wrapper from google.protobuf import descriptor as _descriptor from google.protobuf import message as _message from collections.abc import Iterable as _Iterable, Mapping as _Mapping @@ -6,25 +7,30 @@ from typing import ClassVar as _ClassVar, Optional as _Optional, Union as _Union DESCRIPTOR: _descriptor.FileDescriptor +class DescriptorPageOrder(int, metaclass=_enum_type_wrapper.EnumTypeWrapper): + __slots__ = () + DESCRIPTOR_PAGE_ORDER_FORWARD: _ClassVar[DescriptorPageOrder] + DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST: _ClassVar[DescriptorPageOrder] +DESCRIPTOR_PAGE_ORDER_FORWARD: DescriptorPageOrder +DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST: DescriptorPageOrder + class Empty(_message.Message): __slots__ = () def __init__(self) -> None: ... class StartRunRequest(_message.Message): - __slots__ = ("flow_name", "input_json", "context_json", "input_files", "run_id", "workflow_selector") - FLOW_NAME_FIELD_NUMBER: _ClassVar[int] + __slots__ = ("input_json", "context_json", "input_files", "run_id", "workflow_selector") INPUT_JSON_FIELD_NUMBER: _ClassVar[int] CONTEXT_JSON_FIELD_NUMBER: _ClassVar[int] INPUT_FILES_FIELD_NUMBER: _ClassVar[int] RUN_ID_FIELD_NUMBER: _ClassVar[int] WORKFLOW_SELECTOR_FIELD_NUMBER: _ClassVar[int] - flow_name: str input_json: str context_json: str input_files: _containers.RepeatedCompositeFieldContainer[FileAttachment] run_id: str workflow_selector: str - def __init__(self, flow_name: _Optional[str] = ..., input_json: _Optional[str] = ..., context_json: _Optional[str] = ..., input_files: _Optional[_Iterable[_Union[FileAttachment, _Mapping]]] = ..., run_id: _Optional[str] = ..., workflow_selector: _Optional[str] = ...) -> None: ... + def __init__(self, input_json: _Optional[str] = ..., context_json: _Optional[str] = ..., input_files: _Optional[_Iterable[_Union[FileAttachment, _Mapping]]] = ..., run_id: _Optional[str] = ..., workflow_selector: _Optional[str] = ...) -> None: ... class FileAttachment(_message.Message): __slots__ = ("field_name", "name", "content", "content_type", "sha256") @@ -78,25 +84,43 @@ class GetRunSnapshotRequest(_message.Message): as_of_sequence: int def __init__(self, run_id: _Optional[str] = ..., operator_instance_id: _Optional[str] = ..., as_of_sequence: _Optional[int] = ...) -> None: ... +class GetLatestRunSnapshotRequest(_message.Message): + __slots__ = ("run_id", "operator_instance_id") + RUN_ID_FIELD_NUMBER: _ClassVar[int] + OPERATOR_INSTANCE_ID_FIELD_NUMBER: _ClassVar[int] + run_id: str + operator_instance_id: str + def __init__(self, run_id: _Optional[str] = ..., operator_instance_id: _Optional[str] = ...) -> None: ... + class ListLogsRequest(_message.Message): - __slots__ = ("page_token", "after_sequence", "page_size") + __slots__ = ("page_token", "after_sequence", "page_size", "before_sequence", "node_id", "order") PAGE_TOKEN_FIELD_NUMBER: _ClassVar[int] AFTER_SEQUENCE_FIELD_NUMBER: _ClassVar[int] PAGE_SIZE_FIELD_NUMBER: _ClassVar[int] + BEFORE_SEQUENCE_FIELD_NUMBER: _ClassVar[int] + NODE_ID_FIELD_NUMBER: _ClassVar[int] + ORDER_FIELD_NUMBER: _ClassVar[int] page_token: str after_sequence: int page_size: int - def __init__(self, page_token: _Optional[str] = ..., after_sequence: _Optional[int] = ..., page_size: _Optional[int] = ...) -> None: ... + before_sequence: int + node_id: str + order: DescriptorPageOrder + def __init__(self, page_token: _Optional[str] = ..., after_sequence: _Optional[int] = ..., page_size: _Optional[int] = ..., before_sequence: _Optional[int] = ..., node_id: _Optional[str] = ..., order: _Optional[_Union[DescriptorPageOrder, str]] = ...) -> None: ... class ListAgentEventsRequest(_message.Message): - __slots__ = ("page_token", "after_event_sequence", "page_size") + __slots__ = ("page_token", "after_event_sequence", "page_size", "before_event_sequence", "order") PAGE_TOKEN_FIELD_NUMBER: _ClassVar[int] AFTER_EVENT_SEQUENCE_FIELD_NUMBER: _ClassVar[int] PAGE_SIZE_FIELD_NUMBER: _ClassVar[int] + BEFORE_EVENT_SEQUENCE_FIELD_NUMBER: _ClassVar[int] + ORDER_FIELD_NUMBER: _ClassVar[int] page_token: str after_event_sequence: int page_size: int - def __init__(self, page_token: _Optional[str] = ..., after_event_sequence: _Optional[int] = ..., page_size: _Optional[int] = ...) -> None: ... + before_event_sequence: int + order: DescriptorPageOrder + def __init__(self, page_token: _Optional[str] = ..., after_event_sequence: _Optional[int] = ..., page_size: _Optional[int] = ..., before_event_sequence: _Optional[int] = ..., order: _Optional[_Union[DescriptorPageOrder, str]] = ...) -> None: ... class ReadTraceRequest(_message.Message): __slots__ = ("run_id", "node_id", "revision", "operator_instance_id") @@ -116,7 +140,7 @@ class ReadDetailRequest(_message.Message): body_token: str def __init__(self, body_token: _Optional[str] = ...) -> None: ... -class StreamRunUpdatesRequest(_message.Message): +class StreamOperatorUpdatesRequest(_message.Message): __slots__ = ("operator_instance_id", "after_sequence") OPERATOR_INSTANCE_ID_FIELD_NUMBER: _ClassVar[int] AFTER_SEQUENCE_FIELD_NUMBER: _ClassVar[int] @@ -130,6 +154,57 @@ class NodeEdges(_message.Message): children: _containers.RepeatedScalarFieldContainer[str] def __init__(self, children: _Optional[_Iterable[str]] = ...) -> None: ... +class WorkflowTopologyMsg(_message.Message): + __slots__ = ("node_ids", "graph", "node_types", "display_names", "agent_field_schemas_json", "agent_instruction_lines") + class GraphEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: NodeEdges + def __init__(self, key: _Optional[str] = ..., value: _Optional[_Union[NodeEdges, _Mapping]] = ...) -> None: ... + class NodeTypesEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: str + def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + class DisplayNamesEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: str + def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + class AgentFieldSchemasJsonEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: str + def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + class AgentInstructionLinesEntry(_message.Message): + __slots__ = ("key", "value") + KEY_FIELD_NUMBER: _ClassVar[int] + VALUE_FIELD_NUMBER: _ClassVar[int] + key: str + value: str + def __init__(self, key: _Optional[str] = ..., value: _Optional[str] = ...) -> None: ... + NODE_IDS_FIELD_NUMBER: _ClassVar[int] + GRAPH_FIELD_NUMBER: _ClassVar[int] + NODE_TYPES_FIELD_NUMBER: _ClassVar[int] + DISPLAY_NAMES_FIELD_NUMBER: _ClassVar[int] + AGENT_FIELD_SCHEMAS_JSON_FIELD_NUMBER: _ClassVar[int] + AGENT_INSTRUCTION_LINES_FIELD_NUMBER: _ClassVar[int] + node_ids: _containers.RepeatedScalarFieldContainer[str] + graph: _containers.MessageMap[str, NodeEdges] + node_types: _containers.ScalarMap[str, str] + display_names: _containers.ScalarMap[str, str] + agent_field_schemas_json: _containers.ScalarMap[str, str] + agent_instruction_lines: _containers.ScalarMap[str, str] + def __init__(self, node_ids: _Optional[_Iterable[str]] = ..., graph: _Optional[_Mapping[str, NodeEdges]] = ..., node_types: _Optional[_Mapping[str, str]] = ..., display_names: _Optional[_Mapping[str, str]] = ..., agent_field_schemas_json: _Optional[_Mapping[str, str]] = ..., agent_instruction_lines: _Optional[_Mapping[str, str]] = ...) -> None: ... + class FlowInfoMsg(_message.Message): __slots__ = ("name", "file_path", "node_ids", "graph", "node_types", "display_names", "cron", "next_run_at", "last_run_at", "workflow_id", "display_name", "root_alias", "relative_file", "builder_symbol", "agent_node_ids", "agent_metadata_json", "webhook_path", "webhook_url", "webhook_active") class GraphEntry(_message.Message): @@ -200,14 +275,6 @@ class FlowInfoMsg(_message.Message): webhook_active: bool def __init__(self, name: _Optional[str] = ..., file_path: _Optional[str] = ..., node_ids: _Optional[_Iterable[str]] = ..., graph: _Optional[_Mapping[str, NodeEdges]] = ..., node_types: _Optional[_Mapping[str, str]] = ..., display_names: _Optional[_Mapping[str, str]] = ..., cron: _Optional[str] = ..., next_run_at: _Optional[float] = ..., last_run_at: _Optional[float] = ..., workflow_id: _Optional[str] = ..., display_name: _Optional[str] = ..., root_alias: _Optional[str] = ..., relative_file: _Optional[str] = ..., builder_symbol: _Optional[str] = ..., agent_node_ids: _Optional[_Iterable[str]] = ..., agent_metadata_json: _Optional[_Mapping[str, str]] = ..., webhook_path: _Optional[str] = ..., webhook_url: _Optional[str] = ..., webhook_active: bool = ...) -> None: ... -class FlowList(_message.Message): - __slots__ = ("flows", "diagnostics") - FLOWS_FIELD_NUMBER: _ClassVar[int] - DIAGNOSTICS_FIELD_NUMBER: _ClassVar[int] - flows: _containers.RepeatedCompositeFieldContainer[FlowInfoMsg] - diagnostics: _containers.RepeatedCompositeFieldContainer[DiscoveryDiagnosticMsg] - def __init__(self, flows: _Optional[_Iterable[_Union[FlowInfoMsg, _Mapping]]] = ..., diagnostics: _Optional[_Iterable[_Union[DiscoveryDiagnosticMsg, _Mapping]]] = ...) -> None: ... - class DiscoveryDiagnosticMsg(_message.Message): __slots__ = ("path", "kind", "message") PATH_FIELD_NUMBER: _ClassVar[int] @@ -218,6 +285,32 @@ class DiscoveryDiagnosticMsg(_message.Message): message: str def __init__(self, path: _Optional[str] = ..., kind: _Optional[str] = ..., message: _Optional[str] = ...) -> None: ... +class ScanTargetMsg(_message.Message): + __slots__ = ("alias", "target_path", "kind") + ALIAS_FIELD_NUMBER: _ClassVar[int] + TARGET_PATH_FIELD_NUMBER: _ClassVar[int] + KIND_FIELD_NUMBER: _ClassVar[int] + alias: str + target_path: str + kind: str + def __init__(self, alias: _Optional[str] = ..., target_path: _Optional[str] = ..., kind: _Optional[str] = ...) -> None: ... + +class CatalogSnapshotMsg(_message.Message): + __slots__ = ("operator_instance_id", "as_of_sequence", "revision", "workflows", "scan_targets", "diagnostics") + OPERATOR_INSTANCE_ID_FIELD_NUMBER: _ClassVar[int] + AS_OF_SEQUENCE_FIELD_NUMBER: _ClassVar[int] + REVISION_FIELD_NUMBER: _ClassVar[int] + WORKFLOWS_FIELD_NUMBER: _ClassVar[int] + SCAN_TARGETS_FIELD_NUMBER: _ClassVar[int] + DIAGNOSTICS_FIELD_NUMBER: _ClassVar[int] + operator_instance_id: str + as_of_sequence: int + revision: int + workflows: _containers.RepeatedCompositeFieldContainer[FlowInfoMsg] + scan_targets: _containers.RepeatedCompositeFieldContainer[ScanTargetMsg] + diagnostics: _containers.RepeatedCompositeFieldContainer[DiscoveryDiagnosticMsg] + def __init__(self, operator_instance_id: _Optional[str] = ..., as_of_sequence: _Optional[int] = ..., revision: _Optional[int] = ..., workflows: _Optional[_Iterable[_Union[FlowInfoMsg, _Mapping]]] = ..., scan_targets: _Optional[_Iterable[_Union[ScanTargetMsg, _Mapping]]] = ..., diagnostics: _Optional[_Iterable[_Union[DiscoveryDiagnosticMsg, _Mapping]]] = ...) -> None: ... + class ResultFileAttachment(_message.Message): __slots__ = ("attachment_id", "name", "content", "media_type", "sha256") ATTACHMENT_ID_FIELD_NUMBER: _ClassVar[int] @@ -241,7 +334,7 @@ class RunResultMsg(_message.Message): def __init__(self, value_json: _Optional[str] = ..., files: _Optional[_Iterable[_Union[ResultFileAttachment, _Mapping]]] = ...) -> None: ... class RunSummaryMsg(_message.Message): - __slots__ = ("run_id", "flow_name", "status", "started_at", "ended_at", "triggered_by", "workflow_id", "workflow_display_name", "created_sequence", "revision") + __slots__ = ("run_id", "flow_name", "status", "started_at", "ended_at", "triggered_by", "workflow_id", "workflow_display_name", "created_sequence", "revision", "triggered_at") RUN_ID_FIELD_NUMBER: _ClassVar[int] FLOW_NAME_FIELD_NUMBER: _ClassVar[int] STATUS_FIELD_NUMBER: _ClassVar[int] @@ -252,6 +345,7 @@ class RunSummaryMsg(_message.Message): WORKFLOW_DISPLAY_NAME_FIELD_NUMBER: _ClassVar[int] CREATED_SEQUENCE_FIELD_NUMBER: _ClassVar[int] REVISION_FIELD_NUMBER: _ClassVar[int] + TRIGGERED_AT_FIELD_NUMBER: _ClassVar[int] run_id: str flow_name: str status: str @@ -262,10 +356,31 @@ class RunSummaryMsg(_message.Message): workflow_display_name: str created_sequence: int revision: int - def __init__(self, run_id: _Optional[str] = ..., flow_name: _Optional[str] = ..., status: _Optional[str] = ..., started_at: _Optional[float] = ..., ended_at: _Optional[float] = ..., triggered_by: _Optional[str] = ..., workflow_id: _Optional[str] = ..., workflow_display_name: _Optional[str] = ..., created_sequence: _Optional[int] = ..., revision: _Optional[int] = ...) -> None: ... + triggered_at: float + def __init__(self, run_id: _Optional[str] = ..., flow_name: _Optional[str] = ..., status: _Optional[str] = ..., started_at: _Optional[float] = ..., ended_at: _Optional[float] = ..., triggered_by: _Optional[str] = ..., workflow_id: _Optional[str] = ..., workflow_display_name: _Optional[str] = ..., created_sequence: _Optional[int] = ..., revision: _Optional[int] = ..., triggered_at: _Optional[float] = ...) -> None: ... + +class TraceHeaderMsg(_message.Message): + __slots__ = ("status", "model", "sub_model", "iterations", "max_iterations", "duration_ms", "usage_json", "telemetry_json") + STATUS_FIELD_NUMBER: _ClassVar[int] + MODEL_FIELD_NUMBER: _ClassVar[int] + SUB_MODEL_FIELD_NUMBER: _ClassVar[int] + ITERATIONS_FIELD_NUMBER: _ClassVar[int] + MAX_ITERATIONS_FIELD_NUMBER: _ClassVar[int] + DURATION_MS_FIELD_NUMBER: _ClassVar[int] + USAGE_JSON_FIELD_NUMBER: _ClassVar[int] + TELEMETRY_JSON_FIELD_NUMBER: _ClassVar[int] + status: str + model: str + sub_model: str + iterations: int + max_iterations: int + duration_ms: int + usage_json: str + telemetry_json: str + def __init__(self, status: _Optional[str] = ..., model: _Optional[str] = ..., sub_model: _Optional[str] = ..., iterations: _Optional[int] = ..., max_iterations: _Optional[int] = ..., duration_ms: _Optional[int] = ..., usage_json: _Optional[str] = ..., telemetry_json: _Optional[str] = ...) -> None: ... class TraceDescriptorMsg(_message.Message): - __slots__ = ("status", "revision", "available", "complete", "event_count", "size_bytes", "latest_event_sequence") + __slots__ = ("status", "revision", "available", "complete", "event_count", "size_bytes", "latest_event_sequence", "header") STATUS_FIELD_NUMBER: _ClassVar[int] REVISION_FIELD_NUMBER: _ClassVar[int] AVAILABLE_FIELD_NUMBER: _ClassVar[int] @@ -273,6 +388,7 @@ class TraceDescriptorMsg(_message.Message): EVENT_COUNT_FIELD_NUMBER: _ClassVar[int] SIZE_BYTES_FIELD_NUMBER: _ClassVar[int] LATEST_EVENT_SEQUENCE_FIELD_NUMBER: _ClassVar[int] + HEADER_FIELD_NUMBER: _ClassVar[int] status: str revision: int available: bool @@ -280,10 +396,11 @@ class TraceDescriptorMsg(_message.Message): event_count: int size_bytes: int latest_event_sequence: int - def __init__(self, status: _Optional[str] = ..., revision: _Optional[int] = ..., available: bool = ..., complete: bool = ..., event_count: _Optional[int] = ..., size_bytes: _Optional[int] = ..., latest_event_sequence: _Optional[int] = ...) -> None: ... + header: TraceHeaderMsg + def __init__(self, status: _Optional[str] = ..., revision: _Optional[int] = ..., available: bool = ..., complete: bool = ..., event_count: _Optional[int] = ..., size_bytes: _Optional[int] = ..., latest_event_sequence: _Optional[int] = ..., header: _Optional[_Union[TraceHeaderMsg, _Mapping]] = ...) -> None: ... class NodeSnapshotMsg(_message.Message): - __slots__ = ("node_id", "name", "node_type", "status", "started_at", "ended_at", "trace", "revision", "event_page_token") + __slots__ = ("node_id", "name", "node_type", "status", "started_at", "ended_at", "trace", "revision", "event_page_token", "error", "running_elapsed_seconds") NODE_ID_FIELD_NUMBER: _ClassVar[int] NAME_FIELD_NUMBER: _ClassVar[int] NODE_TYPE_FIELD_NUMBER: _ClassVar[int] @@ -293,6 +410,8 @@ class NodeSnapshotMsg(_message.Message): TRACE_FIELD_NUMBER: _ClassVar[int] REVISION_FIELD_NUMBER: _ClassVar[int] EVENT_PAGE_TOKEN_FIELD_NUMBER: _ClassVar[int] + ERROR_FIELD_NUMBER: _ClassVar[int] + RUNNING_ELAPSED_SECONDS_FIELD_NUMBER: _ClassVar[int] node_id: str name: str node_type: str @@ -302,23 +421,27 @@ class NodeSnapshotMsg(_message.Message): trace: TraceDescriptorMsg revision: int event_page_token: str - def __init__(self, node_id: _Optional[str] = ..., name: _Optional[str] = ..., node_type: _Optional[str] = ..., status: _Optional[str] = ..., started_at: _Optional[float] = ..., ended_at: _Optional[float] = ..., trace: _Optional[_Union[TraceDescriptorMsg, _Mapping]] = ..., revision: _Optional[int] = ..., event_page_token: _Optional[str] = ...) -> None: ... + error: str + running_elapsed_seconds: float + def __init__(self, node_id: _Optional[str] = ..., name: _Optional[str] = ..., node_type: _Optional[str] = ..., status: _Optional[str] = ..., started_at: _Optional[float] = ..., ended_at: _Optional[float] = ..., trace: _Optional[_Union[TraceDescriptorMsg, _Mapping]] = ..., revision: _Optional[int] = ..., event_page_token: _Optional[str] = ..., error: _Optional[str] = ..., running_elapsed_seconds: _Optional[float] = ...) -> None: ... class RunSnapshotMsg(_message.Message): - __slots__ = ("operator_instance_id", "as_of_sequence", "summary", "nodes", "latest_log_sequence", "log_page_token") + __slots__ = ("operator_instance_id", "as_of_sequence", "summary", "nodes", "latest_log_sequence", "log_page_token", "topology") OPERATOR_INSTANCE_ID_FIELD_NUMBER: _ClassVar[int] AS_OF_SEQUENCE_FIELD_NUMBER: _ClassVar[int] SUMMARY_FIELD_NUMBER: _ClassVar[int] NODES_FIELD_NUMBER: _ClassVar[int] LATEST_LOG_SEQUENCE_FIELD_NUMBER: _ClassVar[int] LOG_PAGE_TOKEN_FIELD_NUMBER: _ClassVar[int] + TOPOLOGY_FIELD_NUMBER: _ClassVar[int] operator_instance_id: str as_of_sequence: int summary: RunSummaryMsg nodes: _containers.RepeatedCompositeFieldContainer[NodeSnapshotMsg] latest_log_sequence: int log_page_token: str - def __init__(self, operator_instance_id: _Optional[str] = ..., as_of_sequence: _Optional[int] = ..., summary: _Optional[_Union[RunSummaryMsg, _Mapping]] = ..., nodes: _Optional[_Iterable[_Union[NodeSnapshotMsg, _Mapping]]] = ..., latest_log_sequence: _Optional[int] = ..., log_page_token: _Optional[str] = ...) -> None: ... + topology: WorkflowTopologyMsg + def __init__(self, operator_instance_id: _Optional[str] = ..., as_of_sequence: _Optional[int] = ..., summary: _Optional[_Union[RunSummaryMsg, _Mapping]] = ..., nodes: _Optional[_Iterable[_Union[NodeSnapshotMsg, _Mapping]]] = ..., latest_log_sequence: _Optional[int] = ..., log_page_token: _Optional[str] = ..., topology: _Optional[_Union[WorkflowTopologyMsg, _Mapping]] = ...) -> None: ... class RunSummaryPage(_message.Message): __slots__ = ("operator_instance_id", "as_of_sequence", "runs", "next_page_token") @@ -361,16 +484,28 @@ class LogPage(_message.Message): def __init__(self, operator_instance_id: _Optional[str] = ..., as_of_sequence: _Optional[int] = ..., logs: _Optional[_Iterable[_Union[LogRecordDescriptorMsg, _Mapping]]] = ..., next_page_token: _Optional[str] = ...) -> None: ... class AgentEventDescriptorMsg(_message.Message): - __slots__ = ("event_sequence", "size_bytes", "body_token", "invocation_id") + __slots__ = ("event_sequence", "size_bytes", "body_token", "invocation_id", "event_kind", "iteration", "duration_ms", "error", "tool_count", "predict_count") EVENT_SEQUENCE_FIELD_NUMBER: _ClassVar[int] SIZE_BYTES_FIELD_NUMBER: _ClassVar[int] BODY_TOKEN_FIELD_NUMBER: _ClassVar[int] INVOCATION_ID_FIELD_NUMBER: _ClassVar[int] + EVENT_KIND_FIELD_NUMBER: _ClassVar[int] + ITERATION_FIELD_NUMBER: _ClassVar[int] + DURATION_MS_FIELD_NUMBER: _ClassVar[int] + ERROR_FIELD_NUMBER: _ClassVar[int] + TOOL_COUNT_FIELD_NUMBER: _ClassVar[int] + PREDICT_COUNT_FIELD_NUMBER: _ClassVar[int] event_sequence: int size_bytes: int body_token: str invocation_id: str - def __init__(self, event_sequence: _Optional[int] = ..., size_bytes: _Optional[int] = ..., body_token: _Optional[str] = ..., invocation_id: _Optional[str] = ...) -> None: ... + event_kind: str + iteration: int + duration_ms: int + error: bool + tool_count: int + predict_count: int + def __init__(self, event_sequence: _Optional[int] = ..., size_bytes: _Optional[int] = ..., body_token: _Optional[str] = ..., invocation_id: _Optional[str] = ..., event_kind: _Optional[str] = ..., iteration: _Optional[int] = ..., duration_ms: _Optional[int] = ..., error: bool = ..., tool_count: _Optional[int] = ..., predict_count: _Optional[int] = ...) -> None: ... class AgentEventPage(_message.Message): __slots__ = ("operator_instance_id", "as_of_sequence", "run_id", "node_id", "events", "next_page_token") @@ -411,12 +546,14 @@ class DetailChunk(_message.Message): def __init__(self, chunk_index: _Optional[int] = ..., data: _Optional[bytes] = ..., eof: bool = ...) -> None: ... class RunCreated(_message.Message): - __slots__ = ("summary", "nodes") + __slots__ = ("summary", "nodes", "topology") SUMMARY_FIELD_NUMBER: _ClassVar[int] NODES_FIELD_NUMBER: _ClassVar[int] + TOPOLOGY_FIELD_NUMBER: _ClassVar[int] summary: RunSummaryMsg nodes: _containers.RepeatedCompositeFieldContainer[NodeSnapshotMsg] - def __init__(self, summary: _Optional[_Union[RunSummaryMsg, _Mapping]] = ..., nodes: _Optional[_Iterable[_Union[NodeSnapshotMsg, _Mapping]]] = ...) -> None: ... + topology: WorkflowTopologyMsg + def __init__(self, summary: _Optional[_Union[RunSummaryMsg, _Mapping]] = ..., nodes: _Optional[_Iterable[_Union[NodeSnapshotMsg, _Mapping]]] = ..., topology: _Optional[_Union[WorkflowTopologyMsg, _Mapping]] = ...) -> None: ... class RunStatusChanged(_message.Message): __slots__ = ("run_id", "status", "started_at", "ended_at", "revision") @@ -433,20 +570,24 @@ class RunStatusChanged(_message.Message): def __init__(self, run_id: _Optional[str] = ..., status: _Optional[str] = ..., started_at: _Optional[float] = ..., ended_at: _Optional[float] = ..., revision: _Optional[int] = ...) -> None: ... class NodeStatusChanged(_message.Message): - __slots__ = ("run_id", "node_id", "status", "started_at", "ended_at", "revision") + __slots__ = ("run_id", "node_id", "status", "started_at", "ended_at", "revision", "error", "running_elapsed_seconds") RUN_ID_FIELD_NUMBER: _ClassVar[int] NODE_ID_FIELD_NUMBER: _ClassVar[int] STATUS_FIELD_NUMBER: _ClassVar[int] STARTED_AT_FIELD_NUMBER: _ClassVar[int] ENDED_AT_FIELD_NUMBER: _ClassVar[int] REVISION_FIELD_NUMBER: _ClassVar[int] + ERROR_FIELD_NUMBER: _ClassVar[int] + RUNNING_ELAPSED_SECONDS_FIELD_NUMBER: _ClassVar[int] run_id: str node_id: str status: str started_at: float ended_at: float revision: int - def __init__(self, run_id: _Optional[str] = ..., node_id: _Optional[str] = ..., status: _Optional[str] = ..., started_at: _Optional[float] = ..., ended_at: _Optional[float] = ..., revision: _Optional[int] = ...) -> None: ... + error: str + running_elapsed_seconds: float + def __init__(self, run_id: _Optional[str] = ..., node_id: _Optional[str] = ..., status: _Optional[str] = ..., started_at: _Optional[float] = ..., ended_at: _Optional[float] = ..., revision: _Optional[int] = ..., error: _Optional[str] = ..., running_elapsed_seconds: _Optional[float] = ...) -> None: ... class LogAppended(_message.Message): __slots__ = ("run_id", "log") @@ -476,8 +617,14 @@ class TraceFinalized(_message.Message): trace: TraceDescriptorMsg def __init__(self, run_id: _Optional[str] = ..., node_id: _Optional[str] = ..., trace: _Optional[_Union[TraceDescriptorMsg, _Mapping]] = ...) -> None: ... -class RunUpdate(_message.Message): - __slots__ = ("sequence", "run_created", "run_status_changed", "node_status_changed", "log_appended", "agent_event_appended", "trace_finalized") +class CatalogReplaced(_message.Message): + __slots__ = ("catalog",) + CATALOG_FIELD_NUMBER: _ClassVar[int] + catalog: CatalogSnapshotMsg + def __init__(self, catalog: _Optional[_Union[CatalogSnapshotMsg, _Mapping]] = ...) -> None: ... + +class OperatorUpdate(_message.Message): + __slots__ = ("sequence", "run_created", "run_status_changed", "node_status_changed", "log_appended", "agent_event_appended", "trace_finalized", "catalog_replaced") SEQUENCE_FIELD_NUMBER: _ClassVar[int] RUN_CREATED_FIELD_NUMBER: _ClassVar[int] RUN_STATUS_CHANGED_FIELD_NUMBER: _ClassVar[int] @@ -485,6 +632,7 @@ class RunUpdate(_message.Message): LOG_APPENDED_FIELD_NUMBER: _ClassVar[int] AGENT_EVENT_APPENDED_FIELD_NUMBER: _ClassVar[int] TRACE_FINALIZED_FIELD_NUMBER: _ClassVar[int] + CATALOG_REPLACED_FIELD_NUMBER: _ClassVar[int] sequence: int run_created: RunCreated run_status_changed: RunStatusChanged @@ -492,7 +640,8 @@ class RunUpdate(_message.Message): log_appended: LogAppended agent_event_appended: AgentEventAppended trace_finalized: TraceFinalized - def __init__(self, sequence: _Optional[int] = ..., run_created: _Optional[_Union[RunCreated, _Mapping]] = ..., run_status_changed: _Optional[_Union[RunStatusChanged, _Mapping]] = ..., node_status_changed: _Optional[_Union[NodeStatusChanged, _Mapping]] = ..., log_appended: _Optional[_Union[LogAppended, _Mapping]] = ..., agent_event_appended: _Optional[_Union[AgentEventAppended, _Mapping]] = ..., trace_finalized: _Optional[_Union[TraceFinalized, _Mapping]] = ...) -> None: ... + catalog_replaced: CatalogReplaced + def __init__(self, sequence: _Optional[int] = ..., run_created: _Optional[_Union[RunCreated, _Mapping]] = ..., run_status_changed: _Optional[_Union[RunStatusChanged, _Mapping]] = ..., node_status_changed: _Optional[_Union[NodeStatusChanged, _Mapping]] = ..., log_appended: _Optional[_Union[LogAppended, _Mapping]] = ..., agent_event_appended: _Optional[_Union[AgentEventAppended, _Mapping]] = ..., trace_finalized: _Optional[_Union[TraceFinalized, _Mapping]] = ..., catalog_replaced: _Optional[_Union[CatalogReplaced, _Mapping]] = ...) -> None: ... class ResetRequired(_message.Message): __slots__ = ("history_floor", "latest_sequence") @@ -502,12 +651,12 @@ class ResetRequired(_message.Message): latest_sequence: int def __init__(self, history_floor: _Optional[int] = ..., latest_sequence: _Optional[int] = ...) -> None: ... -class RunUpdateEnvelope(_message.Message): +class OperatorUpdateEnvelope(_message.Message): __slots__ = ("operator_instance_id", "update", "reset_required") OPERATOR_INSTANCE_ID_FIELD_NUMBER: _ClassVar[int] UPDATE_FIELD_NUMBER: _ClassVar[int] RESET_REQUIRED_FIELD_NUMBER: _ClassVar[int] operator_instance_id: str - update: RunUpdate + update: OperatorUpdate reset_required: ResetRequired - def __init__(self, operator_instance_id: _Optional[str] = ..., update: _Optional[_Union[RunUpdate, _Mapping]] = ..., reset_required: _Optional[_Union[ResetRequired, _Mapping]] = ...) -> None: ... + def __init__(self, operator_instance_id: _Optional[str] = ..., update: _Optional[_Union[OperatorUpdate, _Mapping]] = ..., reset_required: _Optional[_Union[ResetRequired, _Mapping]] = ...) -> None: ... diff --git a/src/runtime/operator/proto/operator_pb2_grpc.py b/src/runtime/operator/proto/operator_pb2_grpc.py index 775e6f4..59fc129 100644 --- a/src/runtime/operator/proto/operator_pb2_grpc.py +++ b/src/runtime/operator/proto/operator_pb2_grpc.py @@ -40,10 +40,10 @@ def __init__(self, channel): Args: channel: A grpc.Channel. """ - self.ListFlows = channel.unary_unary( - '/avalanche.operator.OperatorService/ListFlows', + self.GetCatalog = channel.unary_unary( + '/avalanche.operator.OperatorService/GetCatalog', request_serializer=operator__pb2.Empty.SerializeToString, - response_deserializer=operator__pb2.FlowList.FromString, + response_deserializer=operator__pb2.CatalogSnapshotMsg.FromString, _registered_method=True) self.StartRun = channel.unary_unary( '/avalanche.operator.OperatorService/StartRun', @@ -70,6 +70,11 @@ def __init__(self, channel): request_serializer=operator__pb2.GetRunSnapshotRequest.SerializeToString, response_deserializer=operator__pb2.RunSnapshotMsg.FromString, _registered_method=True) + self.GetLatestRunSnapshot = channel.unary_unary( + '/avalanche.operator.OperatorService/GetLatestRunSnapshot', + request_serializer=operator__pb2.GetLatestRunSnapshotRequest.SerializeToString, + response_deserializer=operator__pb2.RunSnapshotMsg.FromString, + _registered_method=True) self.ListLogs = channel.unary_unary( '/avalanche.operator.OperatorService/ListLogs', request_serializer=operator__pb2.ListLogsRequest.SerializeToString, @@ -90,10 +95,10 @@ def __init__(self, channel): request_serializer=operator__pb2.ReadDetailRequest.SerializeToString, response_deserializer=operator__pb2.DetailChunk.FromString, _registered_method=True) - self.StreamRunUpdates = channel.unary_stream( - '/avalanche.operator.OperatorService/StreamRunUpdates', - request_serializer=operator__pb2.StreamRunUpdatesRequest.SerializeToString, - response_deserializer=operator__pb2.RunUpdateEnvelope.FromString, + self.StreamOperatorUpdates = channel.unary_stream( + '/avalanche.operator.OperatorService/StreamOperatorUpdates', + request_serializer=operator__pb2.StreamOperatorUpdatesRequest.SerializeToString, + response_deserializer=operator__pb2.OperatorUpdateEnvelope.FromString, _registered_method=True) @@ -106,7 +111,7 @@ class OperatorServiceServicer(object): """ - def ListFlows(self, request, context): + def GetCatalog(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -142,6 +147,12 @@ def GetRunSnapshot(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') + def GetLatestRunSnapshot(self, request, context): + """Missing associated documentation comment in .proto file.""" + context.set_code(grpc.StatusCode.UNIMPLEMENTED) + context.set_details('Method not implemented!') + raise NotImplementedError('Method not implemented!') + def ListLogs(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) @@ -166,7 +177,7 @@ def ReadDetail(self, request, context): context.set_details('Method not implemented!') raise NotImplementedError('Method not implemented!') - def StreamRunUpdates(self, request, context): + def StreamOperatorUpdates(self, request, context): """Missing associated documentation comment in .proto file.""" context.set_code(grpc.StatusCode.UNIMPLEMENTED) context.set_details('Method not implemented!') @@ -175,10 +186,10 @@ def StreamRunUpdates(self, request, context): def add_OperatorServiceServicer_to_server(servicer, server): rpc_method_handlers = { - 'ListFlows': grpc.unary_unary_rpc_method_handler( - servicer.ListFlows, + 'GetCatalog': grpc.unary_unary_rpc_method_handler( + servicer.GetCatalog, request_deserializer=operator__pb2.Empty.FromString, - response_serializer=operator__pb2.FlowList.SerializeToString, + response_serializer=operator__pb2.CatalogSnapshotMsg.SerializeToString, ), 'StartRun': grpc.unary_unary_rpc_method_handler( servicer.StartRun, @@ -205,6 +216,11 @@ def add_OperatorServiceServicer_to_server(servicer, server): request_deserializer=operator__pb2.GetRunSnapshotRequest.FromString, response_serializer=operator__pb2.RunSnapshotMsg.SerializeToString, ), + 'GetLatestRunSnapshot': grpc.unary_unary_rpc_method_handler( + servicer.GetLatestRunSnapshot, + request_deserializer=operator__pb2.GetLatestRunSnapshotRequest.FromString, + response_serializer=operator__pb2.RunSnapshotMsg.SerializeToString, + ), 'ListLogs': grpc.unary_unary_rpc_method_handler( servicer.ListLogs, request_deserializer=operator__pb2.ListLogsRequest.FromString, @@ -225,10 +241,10 @@ def add_OperatorServiceServicer_to_server(servicer, server): request_deserializer=operator__pb2.ReadDetailRequest.FromString, response_serializer=operator__pb2.DetailChunk.SerializeToString, ), - 'StreamRunUpdates': grpc.unary_stream_rpc_method_handler( - servicer.StreamRunUpdates, - request_deserializer=operator__pb2.StreamRunUpdatesRequest.FromString, - response_serializer=operator__pb2.RunUpdateEnvelope.SerializeToString, + 'StreamOperatorUpdates': grpc.unary_stream_rpc_method_handler( + servicer.StreamOperatorUpdates, + request_deserializer=operator__pb2.StreamOperatorUpdatesRequest.FromString, + response_serializer=operator__pb2.OperatorUpdateEnvelope.SerializeToString, ), } generic_handler = grpc.method_handlers_generic_handler( @@ -248,7 +264,7 @@ class OperatorService(object): """ @staticmethod - def ListFlows(request, + def GetCatalog(request, target, options=(), channel_credentials=None, @@ -261,9 +277,9 @@ def ListFlows(request, return grpc.experimental.unary_unary( request, target, - '/avalanche.operator.OperatorService/ListFlows', + '/avalanche.operator.OperatorService/GetCatalog', operator__pb2.Empty.SerializeToString, - operator__pb2.FlowList.FromString, + operator__pb2.CatalogSnapshotMsg.FromString, options, channel_credentials, insecure, @@ -409,6 +425,33 @@ def GetRunSnapshot(request, metadata, _registered_method=True) + @staticmethod + def GetLatestRunSnapshot(request, + target, + options=(), + channel_credentials=None, + call_credentials=None, + insecure=False, + compression=None, + wait_for_ready=None, + timeout=None, + metadata=None): + return grpc.experimental.unary_unary( + request, + target, + '/avalanche.operator.OperatorService/GetLatestRunSnapshot', + operator__pb2.GetLatestRunSnapshotRequest.SerializeToString, + operator__pb2.RunSnapshotMsg.FromString, + options, + channel_credentials, + insecure, + call_credentials, + compression, + wait_for_ready, + timeout, + metadata, + _registered_method=True) + @staticmethod def ListLogs(request, target, @@ -518,7 +561,7 @@ def ReadDetail(request, _registered_method=True) @staticmethod - def StreamRunUpdates(request, + def StreamOperatorUpdates(request, target, options=(), channel_credentials=None, @@ -531,9 +574,9 @@ def StreamRunUpdates(request, return grpc.experimental.unary_stream( request, target, - '/avalanche.operator.OperatorService/StreamRunUpdates', - operator__pb2.StreamRunUpdatesRequest.SerializeToString, - operator__pb2.RunUpdateEnvelope.FromString, + '/avalanche.operator.OperatorService/StreamOperatorUpdates', + operator__pb2.StreamOperatorUpdatesRequest.SerializeToString, + operator__pb2.OperatorUpdateEnvelope.FromString, options, channel_credentials, insecure, diff --git a/src/runtime/operator/registry.py b/src/runtime/operator/registry.py index e9209a2..273f826 100644 --- a/src/runtime/operator/registry.py +++ b/src/runtime/operator/registry.py @@ -5,6 +5,7 @@ import json import threading from collections import defaultdict +from dataclasses import replace from types import MappingProxyType from typing import Callable @@ -13,6 +14,7 @@ from .discovery import ConfiguredRoot, configure_roots, discover, load_builder from .models import ( CatalogView, + ScanTargetInfo, WorkflowDescriptor, WorkflowDiscoveryDiagnostic, WorkflowInfo, @@ -33,37 +35,73 @@ def __init__(self, selector: str, candidate_ids: tuple[str, ...]) -> None: ) -def workflow_to_info( - workflow: Workflow, - file_path: str, - *, - workflow_id: str = "", - builder_symbol: str = "", - root_alias: str = "", -) -> WorkflowInfo: - """Convert a Workflow object to the public flat compatibility model.""" - node_ids = workflow._topological_sort() - node_types = {nid: workflow.nodes[nid].node.node_type.value for nid in node_ids} - display_names = {nid: display_name_from_id(nid) for nid in node_ids} - agent_node_ids = [] - agent_metadata_json = {} - for nid in node_ids: - spec = getattr(workflow.nodes[nid].node.fn, "__agent_step__", None) +def agent_metadata_for_workflow(workflow: Workflow, node_ids: list[str]) -> dict[str, str]: + """Serialize stable agent declaration metadata for current-catalog projections.""" + metadata_by_node: dict[str, str] = {} + for node_id in node_ids: + spec = getattr(workflow.nodes[node_id].node.fn, "__agent_step__", None) if spec is None: continue - agent_node_ids.append(nid) try: metadata = spec.declaration_metadata(workflow.agent_defaults) - agent_metadata_json[nid] = json.dumps( + metadata_by_node[node_id] = json.dumps( metadata, ensure_ascii=False, separators=(",", ":"), sort_keys=True ) except Exception as exc: - agent_metadata_json[nid] = json.dumps( + metadata_by_node[node_id] = json.dumps( {"error": str(exc) or type(exc).__name__}, ensure_ascii=False, separators=(",", ":"), sort_keys=True, ) + return metadata_by_node + + +def agent_field_schemas_for_workflow(workflow: Workflow, node_ids: list[str]) -> dict[str, str]: + """Serialize only agent invocation field schemas for immutable run topology.""" + schemas_by_node: dict[str, str] = {} + for node_id in node_ids: + spec = getattr(workflow.nodes[node_id].node.fn, "__agent_step__", None) + if spec is None: + continue + schemas_by_node[node_id] = json.dumps( + spec.field_schema_metadata(), + ensure_ascii=False, + separators=(",", ":"), + sort_keys=True, + ) + return schemas_by_node + + +def agent_instruction_lines_for_workflow( + workflow: Workflow, node_ids: list[str] +) -> dict[str, str]: + """Serialize stable agent signature instruction summaries for a run topology.""" + lines_by_node: dict[str, str] = {} + for node_id in node_ids: + spec = getattr(workflow.nodes[node_id].node.fn, "__agent_step__", None) + if spec is None: + continue + instruction_line = spec.signature_instruction_line() + if instruction_line: + lines_by_node[node_id] = instruction_line + return lines_by_node + + +def workflow_to_info( + workflow: Workflow, + file_path: str, + *, + workflow_id: str = "", + builder_symbol: str = "", + root_alias: str = "", +) -> WorkflowInfo: + """Convert a Workflow object to the public flat compatibility model.""" + node_ids = workflow._topological_sort() + node_types = {nid: workflow.nodes[nid].node.node_type.value for nid in node_ids} + display_names = {nid: display_name_from_id(nid) for nid in node_ids} + agent_metadata_json = agent_metadata_for_workflow(workflow, node_ids) + agent_node_ids = list(agent_metadata_json) return WorkflowInfo( name=workflow.name, display_name=workflow.name, @@ -122,6 +160,13 @@ def view(self) -> CatalogView: with self._lock: return self._view + def restore_view(self, rejected: CatalogView, previous: CatalogView) -> None: + """Restore the last valid view after downstream reconciliation rejects a candidate.""" + with self._lock: + if self._view is not rejected: + raise RuntimeError("Workflow catalog changed before candidate rollback") + self._view = previous + @property def configured_roots(self) -> tuple[ConfiguredRoot, ...]: """Return the normalized workflow roots used by the current catalog.""" @@ -134,17 +179,84 @@ def scan( *, validate: Callable[[tuple[WorkflowDescriptor, ...]], object] | None = None, ) -> CatalogView: - """Build a complete catalog off-lock, then atomically install it.""" + """Configure roots and atomically install one complete valid catalog.""" roots = configure_roots(paths) + with self._lock: + self._scan_paths = tuple(paths) + self._roots = roots + return self._scan_roots(roots, validate=validate) + + def rescan( + self, + *, + validate: Callable[[tuple[WorkflowDescriptor, ...]], object] | None = None, + ) -> CatalogView: + """Refresh configured roots while preserving the last valid catalog.""" + with self._lock: + roots = self._roots + if not roots: + return self.view + return self._scan_roots(roots, validate=validate) + + def _scan_roots( + self, + roots: tuple[ConfiguredRoot, ...], + *, + validate: Callable[[tuple[WorkflowDescriptor, ...]], object] | None, + ) -> CatalogView: descriptors, diagnostics = discover(roots, timeout=self._discovery_timeout) - if validate is not None: - validate(descriptors) + candidate_diagnostics = list(diagnostics) + try: + if validate is not None: + validate(descriptors) + except ValueError as exc: + candidate_diagnostics.append( + WorkflowDiscoveryDiagnostic( + path=", ".join(str(root.target) for root in roots), + kind="invalid_catalog", + message=str(exc), + ) + ) by_id: dict[str, WorkflowDescriptor] = {} for descriptor in descriptors: if descriptor.workflow_id in by_id: - raise ValueError(f"Duplicate canonical workflow ID: {descriptor.workflow_id}") + candidate_diagnostics.append( + WorkflowDiscoveryDiagnostic( + path=descriptor.locator.relative_file, + kind="invalid_catalog", + message=f"Duplicate canonical workflow ID: {descriptor.workflow_id}", + ) + ) + break by_id[descriptor.workflow_id] = descriptor + + scan_targets = tuple( + ScanTargetInfo( + alias=root.alias, + target_path=str(root.target), + kind="directory" if root.target == root.path else "file", + ) + for root in roots + ) + diagnostics_tuple = tuple(candidate_diagnostics) + candidate_failed = any(item.kind != "skipped" for item in diagnostics_tuple) + if candidate_failed: + with self._lock: + current = self._view + if ( + current.scan_targets == scan_targets + and current.diagnostics == diagnostics_tuple + ): + return current + self._view = replace( + current, + scan_targets=scan_targets, + diagnostics=diagnostics_tuple, + ) + return self._view + + by_id = dict(sorted(by_id.items())) short_names: defaultdict[str, list[str]] = defaultdict(list) for descriptor in descriptors: short_names[descriptor.display_name].append(descriptor.workflow_id) @@ -153,28 +265,24 @@ def scan( name: tuple(sorted(set(candidate_ids))) for name, candidate_ids in short_names.items() } - view = CatalogView( - by_id=MappingProxyType(dict(sorted(by_id.items()))), - short_names=MappingProxyType(dict(sorted(frozen_short_names.items()))), - diagnostics=diagnostics, - ) with self._lock: - self._scan_paths = tuple(paths) - self._roots = roots + current = self._view + if ( + current.by_id == by_id + and current.short_names == frozen_short_names + and current.scan_targets == scan_targets + and current.diagnostics == diagnostics_tuple + ): + return current + view = CatalogView( + revision=current.revision + 1, + by_id=MappingProxyType(by_id), + short_names=MappingProxyType(dict(sorted(frozen_short_names.items()))), + scan_targets=scan_targets, + diagnostics=diagnostics_tuple, + ) self._view = view - return view - - def rescan( - self, - *, - validate: Callable[[tuple[WorkflowDescriptor, ...]], object] | None = None, - ) -> CatalogView: - """Refresh configured roots without retaining a last-good descriptor.""" - with self._lock: - paths = list(self._scan_paths) - if not paths: - return self.view - return self.scan(paths, validate=validate) + return view def resolve(self, selector: str) -> WorkflowDescriptor: descriptor, _ = self.resolve_source(selector) @@ -210,8 +318,9 @@ def register(self, builder: Callable[[], Workflow], file_path: str = "") with self._lock: self._manual[workflow.name] = (builder, info) - def list_workflows(self) -> list[WorkflowInfo]: - scanned = [descriptor_to_info(item) for item in self.descriptors()] + def list_workflows(self, view: CatalogView | None = None) -> list[WorkflowInfo]: + catalog = view if view is not None else self.view + scanned = [descriptor_to_info(item) for item in catalog.by_id.values()] with self._lock: manual = [entry[1] for entry in self._manual.values()] return scanned + manual diff --git a/src/runtime/operator/run_worker.py b/src/runtime/operator/run_worker.py index 6186b02..b806f11 100644 --- a/src/runtime/operator/run_worker.py +++ b/src/runtime/operator/run_worker.py @@ -24,6 +24,7 @@ from ..executor import Executor, LocalExecutor, RayExecutor from .hooks import RunHooks from .models import display_name_from_id +from .registry import agent_field_schemas_for_workflow, agent_instruction_lines_for_workflow from .result_store import ( ResultPublicationCancelledError, detach_transferred_bundle_descriptor, @@ -334,6 +335,8 @@ def _workflow_metadata(workflow: Workflow) -> dict[str, Any]: node_id: workflow.nodes[node_id].node.node_type.value for node_id in node_ids }, "display_names": {node_id: display_name_from_id(node_id) for node_id in node_ids}, + "agent_field_schemas_json": agent_field_schemas_for_workflow(workflow, node_ids), + "agent_instruction_lines": agent_instruction_lines_for_workflow(workflow, node_ids), } @@ -362,12 +365,12 @@ def _install_log_capture(event_queue: Any) -> None: root = logging.getLogger() root.handlers.clear() root.addHandler(_QueueLogHandler(event_queue)) - root.setLevel(logging.DEBUG) + root.setLevel(logging.INFO) class _QueueLogHandler(logging.Handler): def __init__(self, event_queue: Any, node_id: str | None = None) -> None: - super().__init__(logging.DEBUG) + super().__init__(logging.INFO) self._queue = event_queue self._node_id = node_id @@ -554,7 +557,7 @@ async def async_wrapper(*args: Any, **kwargs: Any) -> Any: old_level = root_logger.level handler = _QueueLogHandler(ray_log_queue, node_id) root_logger.addHandler(handler) - root_logger.setLevel(logging.DEBUG) + root_logger.setLevel(logging.INFO) sys.stdout, sys.stderr = stdout, stderr try: return await fn(*args, **kwargs) @@ -576,7 +579,7 @@ def wrapper(*args: Any, **kwargs: Any) -> Any: old_level = root_logger.level handler = _QueueLogHandler(ray_log_queue, node_id) root_logger.addHandler(handler) - root_logger.setLevel(logging.DEBUG) + root_logger.setLevel(logging.INFO) sys.stdout, sys.stderr = stdout, stderr try: return fn(*args, **kwargs) diff --git a/src/runtime/operator/server.py b/src/runtime/operator/server.py index 6a2f03f..4fcdbc9 100644 --- a/src/runtime/operator/server.py +++ b/src/runtime/operator/server.py @@ -18,12 +18,11 @@ from ._grpc import _BOUNDED_MESSAGE_OPTIONS from .convert import ( agent_event_descriptor_to_proto, - discovery_diagnostic_to_proto, + catalog_snapshot_to_proto, log_record_descriptor_to_proto, + operator_update_envelope_to_proto, run_snapshot_to_proto, run_summary_to_proto, - run_update_envelope_to_proto, - workflow_info_to_proto, ) from .operator import ( InvalidRunIdError, @@ -50,14 +49,8 @@ class OperatorServicer(pb_grpc.OperatorServiceServicer): def __init__(self, operator: Operator) -> None: self._op = operator - def ListFlows(self, request, context): # noqa: N802 - workflows = self._op.list_workflows() - return pb.FlowList( - flows=[workflow_info_to_proto(p) for p in workflows], - diagnostics=[ - discovery_diagnostic_to_proto(item) for item in self._op.list_diagnostics() - ], - ) + def GetCatalog(self, request, context): # noqa: N802 + return catalog_snapshot_to_proto(self._op.get_catalog()) def StartRun(self, request, context): # noqa: N802 try: @@ -66,10 +59,9 @@ def StartRun(self, request, context): # noqa: N802 except ValueError as exc: context.abort(grpc.StatusCode.INVALID_ARGUMENT, str(exc)) - selector = request.workflow_selector or request.flow_name try: run_id = self._op.start_run( - selector, + request.workflow_selector, run_id=request.run_id or None, input=run_input, context=run_context, @@ -140,6 +132,18 @@ def GetRunSnapshot(self, request, context): # noqa: N802 context.abort(grpc.StatusCode.NOT_FOUND, f"Run {request.run_id} not found") return run_snapshot_to_proto(snapshot) + def GetLatestRunSnapshot(self, request, context): # noqa: N802 + try: + snapshot = self._op.get_latest_run_snapshot( + request.run_id, + operator_instance_id=request.operator_instance_id, + ) + except StructuralBaselineUnavailableError as exc: + context.abort(grpc.StatusCode.FAILED_PRECONDITION, str(exc)) + if snapshot is None: + context.abort(grpc.StatusCode.NOT_FOUND, f"Run {request.run_id} not found") + return run_snapshot_to_proto(snapshot) + def ListLogs(self, request, context): # noqa: N802 if not request.page_token: context.abort( @@ -151,6 +155,9 @@ def ListLogs(self, request, context): # noqa: N802 page_token=request.page_token, after_sequence=request.after_sequence, page_size=request.page_size, + before_sequence=request.before_sequence, + node_id=request.node_id, + order=request.order, ) except StructuralBaselineUnavailableError as exc: context.abort(grpc.StatusCode.FAILED_PRECONDITION, str(exc)) @@ -176,6 +183,8 @@ def ListAgentEvents(self, request, context): # noqa: N802 page_token=request.page_token, after_event_sequence=request.after_event_sequence, page_size=request.page_size, + before_event_sequence=request.before_event_sequence, + order=request.order, ) except StructuralBaselineUnavailableError as exc: context.abort(grpc.StatusCode.FAILED_PRECONDITION, str(exc)) @@ -237,9 +246,9 @@ def ReadDetail(self, request, context): # noqa: N802 eof=offset + len(chunk) == len(data), ) - def StreamRunUpdates(self, request, context): # noqa: N802 - """Replay typed updates for one operator epoch, or require a reset.""" - subscription = self._op.subscribe_run_updates( + def StreamOperatorUpdates(self, request, context): # noqa: N802 + """Replay typed operator updates for one epoch, or require a reset.""" + subscription = self._op.subscribe_operator_updates( request.operator_instance_id, request.after_sequence, ) @@ -250,11 +259,11 @@ def StreamRunUpdates(self, request, context): # noqa: N802 envelope = subscription.get(timeout=1.0) except queue.Empty: continue - yield run_update_envelope_to_proto(envelope) + yield operator_update_envelope_to_proto(envelope) if envelope.reset_required is not None: return finally: - self._op.unsubscribe_run_updates(subscription) + self._op.unsubscribe_operator_updates(subscription) def serve( diff --git a/src/runtime/operator/web.py b/src/runtime/operator/web.py new file mode 100644 index 0000000..7968b13 --- /dev/null +++ b/src/runtime/operator/web.py @@ -0,0 +1,348 @@ +"""In-process gRPC-Web and static asset listener for the local operator UI.""" + +from __future__ import annotations + +import logging +import mimetypes +import select +import socket +import struct +import threading +from collections.abc import Callable, Iterator +from dataclasses import dataclass +from http import HTTPStatus +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path +from types import MappingProxyType +from urllib.parse import unquote, urlsplit + +import grpc +from google.protobuf import message_factory +from google.protobuf.message import DecodeError, Message + +from .operator import Operator +from .proto import operator_pb2 as pb +from .server import OperatorServicer + +logger = logging.getLogger(__name__) + +DEFAULT_WEB_HOST = "127.0.0.1" +DEFAULT_WEB_PORT = 7435 +_GRPC_WEB_CONTENT_TYPE = "application/grpc-web+proto" +_GRPC_SERVICE_PATH = "/avalanche.operator.OperatorService/" +_FRAME_HEADER_BYTES = 5 +_MAX_REQUEST_BYTES = 4 * 1024 * 1024 + + +@dataclass(frozen=True) +class _RpcMethod: + request_type: type[Message] + response_type: type[Message] + server_streaming: bool = False + + +def _rpc_methods() -> MappingProxyType[str, _RpcMethod]: + service = pb.DESCRIPTOR.services_by_name["OperatorService"] + return MappingProxyType( + { + descriptor.name: _RpcMethod( + request_type=message_factory.GetMessageClass(descriptor.input_type), + response_type=message_factory.GetMessageClass(descriptor.output_type), + server_streaming=descriptor.server_streaming, + ) + for descriptor in service.methods + } + ) + + +_RPC_METHODS = _rpc_methods() + + +class _WebRpcAbortError(Exception): + def __init__(self, code: grpc.StatusCode, detail: str) -> None: + super().__init__(detail) + self.code = code + self.detail = detail + + +class _WebRpcContext: + def __init__(self, active: Callable[[], bool]) -> None: + self._active = active + + def abort(self, code: grpc.StatusCode, detail: str) -> None: + raise _WebRpcAbortError(code, detail) + + def is_active(self) -> bool: + return self._active() + + def send_initial_metadata(self, metadata: tuple[()]) -> None: + del metadata + + +class _BrowserHTTPServer(ThreadingHTTPServer): + daemon_threads = True + + def __init__( + self, + server_address: tuple[str, int], + operator: Operator, + asset_root: Path, + ) -> None: + self.operator_servicer = OperatorServicer(operator) + self.asset_root = asset_root + self.stopping = threading.Event() + super().__init__(server_address, _BrowserRequestHandler) + + +class _BrowserRequestHandler(BaseHTTPRequestHandler): + protocol_version = "HTTP/1.1" + server: _BrowserHTTPServer + + def do_GET(self) -> None: # noqa: N802 + self._serve_asset() + + def do_POST(self) -> None: # noqa: N802 + method_name = urlsplit(self.path).path.removeprefix(_GRPC_SERVICE_PATH) + method = _RPC_METHODS.get(method_name) + if method is None or urlsplit(self.path).path != f"{_GRPC_SERVICE_PATH}{method_name}": + self.send_error(HTTPStatus.NOT_FOUND) + return + content_type = self.headers.get_content_type() + if content_type != _GRPC_WEB_CONTENT_TYPE: + self.send_error(HTTPStatus.UNSUPPORTED_MEDIA_TYPE) + return + try: + request = _decode_request(self.rfile.read(self._request_content_length()), method) + except (DecodeError, ValueError) as exc: + self._send_grpc_error(grpc.StatusCode.INVALID_ARGUMENT, str(exc)) + return + context = _WebRpcContext(self._request_is_active) + handler = getattr(self.server.operator_servicer, method_name) + try: + result = handler(request, context) + if method.server_streaming: + self._send_stream(iter(result)) + else: + self._send_unary(result) + except _WebRpcAbortError as exc: + self._send_grpc_error(exc.code, exc.detail) + except (BrokenPipeError, ConnectionResetError): + return + except Exception: + logger.exception("Unhandled gRPC-Web method failure: %s", method_name) + self._send_grpc_error(grpc.StatusCode.INTERNAL, "internal operator error") + + def do_OPTIONS(self) -> None: # noqa: N802 + self.send_response(HTTPStatus.NO_CONTENT) + self.send_header("Allow", "GET, POST, OPTIONS") + self.send_header("Content-Length", "0") + self.end_headers() + + def _request_content_length(self) -> int: + raw = self.headers.get("Content-Length") + if raw is None: + raise ValueError("Content-Length is required") + try: + length = int(raw) + except ValueError as exc: + raise ValueError("Content-Length must be an integer") from exc + if not 0 <= length <= _MAX_REQUEST_BYTES: + raise ValueError(f"request body exceeds {_MAX_REQUEST_BYTES} byte limit") + return length + + def _request_is_active(self) -> bool: + if self.server.stopping.is_set(): + return False + try: + readable, _, _ = select.select([self.connection], [], [], 0) + if not readable: + return True + return bool(self.connection.recv(1, socket.MSG_PEEK)) + except OSError: + return False + + def _send_unary(self, response: Message) -> None: + body = _data_frame(response) + _trailer_frame(grpc.StatusCode.OK, "") + self.send_response(HTTPStatus.OK) + self._send_grpc_headers() + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def _send_stream(self, responses: Iterator[Message]) -> None: + self.send_response(HTTPStatus.OK) + self._send_grpc_headers() + self.send_header("Transfer-Encoding", "chunked") + self.end_headers() + try: + try: + for response in responses: + self._write_chunk(_data_frame(response)) + except _WebRpcAbortError as exc: + trailer = _trailer_frame(exc.code, exc.detail) + except (BrokenPipeError, ConnectionResetError): + return + except Exception: + logger.exception("Unhandled gRPC-Web stream failure") + trailer = _trailer_frame(grpc.StatusCode.INTERNAL, "internal operator error") + else: + trailer = _trailer_frame(grpc.StatusCode.OK, "") + try: + self._write_chunk(trailer) + self.wfile.write(b"0\r\n\r\n") + self.wfile.flush() + except (BrokenPipeError, ConnectionResetError): + return + finally: + close = getattr(responses, "close", None) + if close is not None: + close() + + def _send_grpc_error(self, code: grpc.StatusCode, detail: str) -> None: + if self.wfile.closed: + return + body = _trailer_frame(code, detail) + self.send_response(HTTPStatus.OK) + self._send_grpc_headers() + self.send_header("Content-Length", str(len(body))) + self.end_headers() + self.wfile.write(body) + + def _send_grpc_headers(self) -> None: + self.send_header("Content-Type", _GRPC_WEB_CONTENT_TYPE) + self.send_header("X-Content-Type-Options", "nosniff") + self.send_header("Cache-Control", "no-store") + + def _write_chunk(self, data: bytes) -> None: + self.wfile.write(f"{len(data):x}\r\n".encode("ascii")) + self.wfile.write(data) + self.wfile.write(b"\r\n") + self.wfile.flush() + + def _serve_asset(self) -> None: + request_path = unquote(urlsplit(self.path).path) + relative = request_path.lstrip("/") or "index.html" + candidate = (self.server.asset_root / relative).resolve() + try: + candidate.relative_to(self.server.asset_root) + except ValueError: + self.send_error(HTTPStatus.NOT_FOUND) + return + if not candidate.is_file() and "." not in Path(relative).name: + candidate = self.server.asset_root / "index.html" + if not candidate.is_file(): + self.send_error(HTTPStatus.NOT_FOUND) + return + data = candidate.read_bytes() + content_type = mimetypes.guess_type(candidate.name)[0] or "application/octet-stream" + self.send_response(HTTPStatus.OK) + self.send_header("Content-Type", content_type) + self.send_header("Content-Length", str(len(data))) + if candidate.name == "index.html": + self.send_header("Cache-Control", "no-store") + else: + self.send_header("Cache-Control", "public, max-age=31536000, immutable") + self.send_header("X-Content-Type-Options", "nosniff") + self.end_headers() + self.wfile.write(data) + + def log_message(self, format: str, *args: object) -> None: + logger.debug("Browser listener: " + format, *args) + + +class BrowserServer: + """Owned browser listener serving gRPC-Web and the compiled SPA.""" + + def __init__(self, server: _BrowserHTTPServer, thread: threading.Thread) -> None: + self._server = server + self._thread = thread + + @property + def host(self) -> str: + return str(self._server.server_address[0]) + + @property + def port(self) -> int: + return int(self._server.server_address[1]) + + @property + def endpoint(self) -> str: + host = f"[{self.host}]" if ":" in self.host else self.host + return f"http://{host}:{self.port}" + + def close(self) -> None: + if self._server.stopping.is_set(): + return + self._server.stopping.set() + self._server.shutdown() + self._server.server_close() + self._thread.join(timeout=2.0) + + +def start_browser_server( + operator: Operator, + *, + host: str = DEFAULT_WEB_HOST, + port: int = DEFAULT_WEB_PORT, + asset_root: Path | None = None, + trust_non_loopback: bool = False, +) -> BrowserServer: + """Start the loopback-default browser listener for one shared operator.""" + if not _is_loopback_host(host) and not trust_non_loopback: + raise ValueError( + "Non-loopback web UI exposure requires --web-trusted-proxy and an external " + "trusted, authenticated boundary" + ) + root = (asset_root or Path(__file__).with_name("web_assets")).resolve() + server = _BrowserHTTPServer((host, port), operator, root) + thread = threading.Thread( + target=server.serve_forever, + name="avalanche-browser-listener", + daemon=True, + ) + thread.start() + logger.info("Operator web UI listening on %s", BrowserServer(server, thread).endpoint) + return BrowserServer(server, thread) + + +def _decode_request(data: bytes, method: _RpcMethod) -> Message: + if len(data) < _FRAME_HEADER_BYTES: + raise ValueError("gRPC-Web request frame is truncated") + flags, length = struct.unpack(">BI", data[:_FRAME_HEADER_BYTES]) + if flags != 0: + raise ValueError("compressed or trailer request frames are unsupported") + if length != len(data) - _FRAME_HEADER_BYTES: + raise ValueError("gRPC-Web request frame length does not match its payload") + request = method.request_type() + request.ParseFromString(data[_FRAME_HEADER_BYTES:]) + return request + + +def _data_frame(message: Message) -> bytes: + payload = message.SerializeToString() + return struct.pack(">BI", 0, len(payload)) + payload + + +def _trailer_frame(code: grpc.StatusCode, detail: str) -> bytes: + status = code.value[0] + safe_detail = detail.replace("\r", " ").replace("\n", " ") + payload = f"grpc-status: {status}\r\ngrpc-message: {safe_detail}\r\n".encode() + return struct.pack(">BI", 0x80, len(payload)) + payload + + +def _is_loopback_host(host: str) -> bool: + normalized = host[1:-1] if host.startswith("[") and host.endswith("]") else host + if normalized.lower() == "localhost": + return True + try: + return socket.gethostbyname(normalized).startswith("127.") or normalized == "::1" + except OSError: + return False + + +__all__ = [ + "BrowserServer", + "DEFAULT_WEB_HOST", + "DEFAULT_WEB_PORT", + "start_browser_server", +] diff --git a/src/runtime/operator/web_assets/assets/avalanche-diamond-3d-1024-DG4CnLyY.png b/src/runtime/operator/web_assets/assets/avalanche-diamond-3d-1024-DG4CnLyY.png new file mode 100644 index 0000000..ce5121b Binary files /dev/null and b/src/runtime/operator/web_assets/assets/avalanche-diamond-3d-1024-DG4CnLyY.png differ diff --git a/src/runtime/operator/web_assets/assets/editor-Dh6wG2B-.js b/src/runtime/operator/web_assets/assets/editor-Dh6wG2B-.js new file mode 100644 index 0000000..cf7788e --- /dev/null +++ b/src/runtime/operator/web_assets/assets/editor-Dh6wG2B-.js @@ -0,0 +1,10 @@ +let Mo=0,$i=class{constructor(t,e){this.from=t,this.to=e}};class R{constructor(t={}){this.id=Mo++,this.perNode=!!t.perNode,this.deserialize=t.deserialize||(()=>{throw new Error("This node type doesn't define a deserialize function")}),this.combine=t.combine||null}add(t){if(this.perNode)throw new RangeError("Can't add per-node props to node types");return typeof t!="function"&&(t=ot.match(t)),e=>{let i=t(e);return i===void 0?null:[this,i]}}}R.closedBy=new R({deserialize:r=>r.split(" ")});R.openedBy=new R({deserialize:r=>r.split(" ")});R.group=new R({deserialize:r=>r.split(" ")});R.isolate=new R({deserialize:r=>{if(r&&r!="rtl"&&r!="ltr"&&r!="auto")throw new RangeError("Invalid value for isolate: "+r);return r||"auto"}});R.contextHash=new R({perNode:!0});R.lookAhead=new R({perNode:!0});R.mounted=new R({perNode:!0});class De{constructor(t,e,i,s=!1){this.tree=t,this.overlay=e,this.parser=i,this.bracketed=s}static get(t){return t&&t.props&&t.props[R.mounted.id]}}const Po=Object.create(null);class ot{constructor(t,e,i,s=0){this.name=t,this.props=e,this.id=i,this.flags=s}static define(t){let e=t.props&&t.props.length?Object.create(null):Po,i=(t.top?1:0)|(t.skipped?2:0)|(t.error?4:0)|(t.name==null?8:0),s=new ot(t.name||"",e,t.id,i);if(t.props){for(let n of t.props)if(Array.isArray(n)||(n=n(s)),n){if(n[0].perNode)throw new RangeError("Can't store a per-node prop on a node type");e[n[0].id]=n[1]}}return s}prop(t){return this.props[t.id]}get isTop(){return(this.flags&1)>0}get isSkipped(){return(this.flags&2)>0}get isError(){return(this.flags&4)>0}get isAnonymous(){return(this.flags&8)>0}is(t){if(typeof t=="string"){if(this.name==t)return!0;let e=this.prop(R.group);return e?e.indexOf(t)>-1:!1}return this.id==t}static match(t){let e=Object.create(null);for(let i in t)for(let s of i.split(" "))e[s]=t[i];return i=>{for(let s=i.prop(R.group),n=-1;n<(s?s.length:0);n++){let o=e[n<0?i.name:s[n]];if(o)return o}}}}ot.none=new ot("",Object.create(null),0,8);class Hs{constructor(t){this.types=t;for(let e=0;e0;for(let h=this.cursor(o|$.IncludeAnonymous);;){let a=!1;if(h.from<=n&&h.to>=s&&(!l&&h.type.isAnonymous||e(h)!==!1)){if(h.firstChild())continue;a=!0}for(;a&&i&&(l||!h.type.isAnonymous)&&i(h),!h.nextSibling();){if(!h.parent())return;a=!0}}}prop(t){return t.perNode?this.props?this.props[t.id]:void 0:this.type.prop(t)}get propValues(){let t=[];if(this.props)for(let e in this.props)t.push([+e,this.props[e]]);return t}balance(t={}){return this.children.length<=8?this:Ks(ot.none,this.children,this.positions,0,this.children.length,0,this.length,(e,i,s)=>new Q(this.type,e,i,s,this.propValues),t.makeTree||((e,i,s)=>new Q(ot.none,e,i,s)))}static build(t){return Eo(t)}}Q.empty=new Q(ot.none,[],[],0);class Vs{constructor(t,e){this.buffer=t,this.index=e}get id(){return this.buffer[this.index-4]}get start(){return this.buffer[this.index-3]}get end(){return this.buffer[this.index-2]}get size(){return this.buffer[this.index-1]}get pos(){return this.index}next(){this.index-=4}fork(){return new Vs(this.buffer,this.index)}}class $t{constructor(t,e,i){this.buffer=t,this.length=e,this.set=i}get type(){return ot.none}toString(){let t=[];for(let e=0;e0));h=o[h+3]);return l}slice(t,e,i){let s=this.buffer,n=new Uint16Array(e-t),o=0;for(let l=t,h=0;l=t&&et;case 1:return e<=t&&i>t;case 2:return i>t;case 4:return!0}}function Le(r,t,e,i){for(var s;r.from==r.to||(e<1?r.from>=t:r.from>t)||(e>-1?r.to<=t:r.to0?l.length:-1;t!=a;t+=e){let f=l[t],u=h[t]+o.from,c;if(!(!(n&$.EnterBracketed&&f instanceof Q&&(c=De.get(f))&&!c.overlay&&c.bracketed&&i>=u&&i<=u+f.length)&&!ur(s,i,u,u+f.length))){if(f instanceof $t){if(n&$.ExcludeBuffers)continue;let d=f.findChild(0,f.buffer.length,e,i-u,s);if(d>-1)return new zt(new Do(o,f,t,u),null,d)}else if(n&$.IncludeAnonymous||!f.type.isAnonymous||zs(f)){let d;if(!(n&$.IgnoreMounts)&&(d=De.get(f))&&!d.overlay)return new dt(d.tree,u,t,o);let p=new dt(f,u,t,o);return n&$.IncludeAnonymous||!p.type.isAnonymous?p:p.nextChild(e<0?f.children.length-1:0,e,i,s,n)}}}if(n&$.IncludeAnonymous||!o.type.isAnonymous||(o.index>=0?t=o.index+e:t=e<0?-1:o._parent._tree.children.length,o=o._parent,!o))return null}}get firstChild(){return this.nextChild(0,1,0,4)}get lastChild(){return this.nextChild(this._tree.children.length-1,-1,0,4)}childAfter(t){return this.nextChild(0,1,t,2)}childBefore(t){return this.nextChild(this._tree.children.length-1,-1,t,-2)}prop(t){return this._tree.prop(t)}enter(t,e,i=0){let s;if(!(i&$.IgnoreOverlays)&&(s=De.get(this._tree))&&s.overlay){let n=t-this.from,o=i&$.EnterBracketed&&s.bracketed;for(let{from:l,to:h}of s.overlay)if((e>0||o?l<=n:l=n:h>n))return new dt(s.tree,s.overlay[0].from+this.from,-1,this)}return this.nextChild(0,1,t,e,i)}nextSignificantParent(){let t=this;for(;t.type.isAnonymous&&t._parent;)t=t._parent;return t}get parent(){return this._parent?this._parent.nextSignificantParent():null}get nextSibling(){return this._parent&&this.index>=0?this._parent.nextChild(this.index+1,1,0,4):null}get prevSibling(){return this._parent&&this.index>=0?this._parent.nextChild(this.index-1,-1,0,4):null}get tree(){return this._tree}toTree(){return this._tree}toString(){return this._tree.toString()}}function ln(r,t,e,i){let s=r.cursor(),n=[];if(!s.firstChild())return n;if(e!=null){for(let o=!1;!o;)if(o=s.type.is(e),!s.nextSibling())return n}for(;;){if(i!=null&&s.type.is(i))return n;if(s.type.is(t)&&n.push(s.node),!s.nextSibling())return i==null?n:[]}}function os(r,t,e=t.length-1){for(let i=r;e>=0;i=i.parent){if(!i)return!1;if(!i.type.isAnonymous){if(t[e]&&t[e]!=i.name)return!1;e--}}return!0}class Do{constructor(t,e,i,s){this.parent=t,this.buffer=e,this.index=i,this.start=s}}class zt extends cr{get name(){return this.type.name}get from(){return this.context.start+this.context.buffer.buffer[this.index+1]}get to(){return this.context.start+this.context.buffer.buffer[this.index+2]}constructor(t,e,i){super(),this.context=t,this._parent=e,this.index=i,this.type=t.buffer.set.types[t.buffer.buffer[i]]}child(t,e,i){let{buffer:s}=this.context,n=s.findChild(this.index+4,s.buffer[this.index+3],t,e-this.context.start,i);return n<0?null:new zt(this.context,this,n)}get firstChild(){return this.child(1,0,4)}get lastChild(){return this.child(-1,0,4)}childAfter(t){return this.child(1,t,2)}childBefore(t){return this.child(-1,t,-2)}prop(t){return this.type.prop(t)}enter(t,e,i=0){if(i&$.ExcludeBuffers)return null;let{buffer:s}=this.context,n=s.findChild(this.index+4,s.buffer[this.index+3],e>0?1:-1,t-this.context.start,e);return n<0?null:new zt(this.context,this,n)}get parent(){return this._parent||this.context.parent.nextSignificantParent()}externalSibling(t){return this._parent?null:this.context.parent.nextChild(this.context.index+t,t,0,4)}get nextSibling(){let{buffer:t}=this.context,e=t.buffer[this.index+3];return e<(this._parent?t.buffer[this._parent.index+3]:t.buffer.length)?new zt(this.context,this._parent,e):this.externalSibling(1)}get prevSibling(){let{buffer:t}=this.context,e=this._parent?this._parent.index+4:0;return this.index==e?this.externalSibling(-1):new zt(this.context,this._parent,t.findChild(e,this.index,-1,0,4))}get tree(){return null}toTree(){let t=[],e=[],{buffer:i}=this.context,s=this.index+4,n=i.buffer[this.index+3];if(n>s){let o=i.buffer[this.index+1];t.push(i.slice(s,n,o)),e.push(0)}return new Q(this.type,t,e,this.to-this.from)}toString(){return this.context.buffer.childString(this.index)}}function dr(r){if(!r.length)return null;let t=0,e=r[0];for(let n=1;ne.from||o.to=t){let l=new dt(o.tree,o.overlay[0].from+n.from,-1,n);(s||(s=[i])).push(Le(l,t,e,!1))}}return s?dr(s):i}class ls{get name(){return this.type.name}constructor(t,e=0){if(this.buffer=null,this.stack=[],this.index=0,this.bufferNode=null,this.mode=e&~$.EnterBracketed,t instanceof dt)this.yieldNode(t);else{this._tree=t.context.parent,this.buffer=t.context;for(let i=t._parent;i;i=i._parent)this.stack.unshift(i.index);this.bufferNode=t,this.yieldBuf(t.index)}}yieldNode(t){return t?(this._tree=t,this.type=t.type,this.from=t.from,this.to=t.to,!0):!1}yieldBuf(t,e){this.index=t;let{start:i,buffer:s}=this.buffer;return this.type=e||s.set.types[s.buffer[t]],this.from=i+s.buffer[t+1],this.to=i+s.buffer[t+2],!0}yield(t){return t?t instanceof dt?(this.buffer=null,this.yieldNode(t)):(this.buffer=t.context,this.yieldBuf(t.index,t.type)):!1}toString(){return this.buffer?this.buffer.buffer.childString(this.index):this._tree.toString()}enterChild(t,e,i){if(!this.buffer)return this.yield(this._tree.nextChild(t<0?this._tree._tree.children.length-1:0,t,e,i,this.mode));let{buffer:s}=this.buffer,n=s.findChild(this.index+4,s.buffer[this.index+3],t,e-this.buffer.start,i);return n<0?!1:(this.stack.push(this.index),this.yieldBuf(n))}firstChild(){return this.enterChild(1,0,4)}lastChild(){return this.enterChild(-1,0,4)}childAfter(t){return this.enterChild(1,t,2)}childBefore(t){return this.enterChild(-1,t,-2)}enter(t,e,i=this.mode){return this.buffer?i&$.ExcludeBuffers?!1:this.enterChild(1,t,e):this.yield(this._tree.enter(t,e,i))}parent(){if(!this.buffer)return this.yieldNode(this.mode&$.IncludeAnonymous?this._tree._parent:this._tree.parent);if(this.stack.length)return this.yieldBuf(this.stack.pop());let t=this.mode&$.IncludeAnonymous?this.buffer.parent:this.buffer.parent.nextSignificantParent();return this.buffer=null,this.yieldNode(t)}sibling(t){if(!this.buffer)return this._tree._parent?this.yield(this._tree.index<0?null:this._tree._parent.nextChild(this._tree.index+t,t,0,4,this.mode)):!1;let{buffer:e}=this.buffer,i=this.stack.length-1;if(t<0){let s=i<0?0:this.stack[i]+4;if(this.index!=s)return this.yieldBuf(e.findChild(s,this.index,-1,0,4))}else{let s=e.buffer[this.index+3];if(s<(i<0?e.buffer.length:e.buffer[this.stack[i]+3]))return this.yieldBuf(s)}return i<0?this.yield(this.buffer.parent.nextChild(this.buffer.index+t,t,0,4,this.mode)):!1}nextSibling(){return this.sibling(1)}prevSibling(){return this.sibling(-1)}atLastNode(t){let e,i,{buffer:s}=this;if(s){if(t>0){if(this.index-1)for(let n=e+t,o=t<0?-1:i._tree.children.length;n!=o;n+=t){let l=i._tree.children[n];if(this.mode&$.IncludeAnonymous||l instanceof $t||!l.type.isAnonymous||zs(l))return!1}return!0}move(t,e){if(e&&this.enterChild(t,0,4))return!0;for(;;){if(this.sibling(t))return!0;if(this.atLastNode(t)||!this.parent())return!1}}next(t=!0){return this.move(1,t)}prev(t=!0){return this.move(-1,t)}moveTo(t,e=0){for(;(this.from==this.to||(e<1?this.from>=t:this.from>t)||(e>-1?this.to<=t:this.to=0;){for(let o=t;o;o=o._parent)if(o.index==s){if(s==this.index)return o;e=o,i=n+1;break t}s=this.stack[--n]}for(let s=i;s=0;n--){if(n<0)return os(this._tree,t,s);let o=i[e.buffer[this.stack[n]]];if(!o.isAnonymous){if(t[s]&&t[s]!=o.name)return!1;s--}}return!0}}function zs(r){return r.children.some(t=>t instanceof $t||!t.type.isAnonymous||zs(t))}function Eo(r){var t;let{buffer:e,nodeSet:i,maxBufferLength:s=1024,reused:n=[],minRepeatType:o=i.types.length}=r,l=Array.isArray(e)?new Vs(e,e.length):e,h=i.types,a=0,f=0;function u(T,C,S,H,W,K){let{id:P,start:O,end:V,size:z}=l,X=f,Lt=a;if(z<0)if(l.next(),z==-1){let Pt=n[P];S.push(Pt),H.push(O-T);return}else if(z==-3){a=P;return}else if(z==-4){f=P;return}else throw new RangeError(`Unrecognized record size: ${z}`);let Se=h[P],Ue,Qt,nn=O-T;if(V-O<=s&&(Qt=m(l.pos-C,W))){let Pt=new Uint16Array(Qt.size-Qt.skip),ft=l.pos-Qt.size,xt=Pt.length;for(;l.pos>ft;)xt=b(Qt.start,Pt,xt);Ue=new $t(Pt,V-Qt.start,i),nn=Qt.start-T}else{let Pt=l.pos-z;l.next();let ft=[],xt=[],Ut=P>=o?P:-1,ne=0,Ge=V;for(;l.pos>Pt;)Ut>=0&&l.id==Ut&&l.size>=0?(l.end<=Ge-s&&(p(ft,xt,O,ne,l.end,Ge,Ut,X,Lt),ne=ft.length,Ge=l.end),l.next()):K>2500?c(O,Pt,ft,xt):u(O,Pt,ft,xt,Ut,K+1);if(Ut>=0&&ne>0&&ne-1&&ne>0){let rn=d(Se,Lt);Ue=Ks(Se,ft,xt,0,ft.length,0,V-O,rn,rn)}else Ue=g(Se,ft,xt,V-O,X-V,Lt)}S.push(Ue),H.push(nn)}function c(T,C,S,H){let W=[],K=0,P=-1;for(;l.pos>C;){let{id:O,start:V,end:z,size:X}=l;if(X>4)l.next();else{if(P>-1&&V=0;z-=3)O[X++]=W[z],O[X++]=W[z+1]-V,O[X++]=W[z+2]-V,O[X++]=X;S.push(new $t(O,W[2]-V,i)),H.push(V-T)}}function d(T,C){return(S,H,W)=>{let K=0,P=S.length-1,O,V;if(P>=0&&(O=S[P])instanceof Q){if(!P&&O.type==T&&O.length==W)return O;(V=O.prop(R.lookAhead))&&(K=H[P]+O.length+V)}return g(T,S,H,W,K,C)}}function p(T,C,S,H,W,K,P,O,V){let z=[],X=[];for(;T.length>H;)z.push(T.pop()),X.push(C.pop()+S-W);T.push(g(i.types[P],z,X,K-W,O-K,V)),C.push(W-S)}function g(T,C,S,H,W,K,P){if(K){let O=[R.contextHash,K];P=P?[O].concat(P):[O]}if(W>25){let O=[R.lookAhead,W];P=P?[O].concat(P):[O]}return new Q(T,C,S,H,P)}function m(T,C){let S=l.fork(),H=0,W=0,K=0,P=S.end-s,O={size:0,start:0,skip:0};t:for(let V=S.pos-T;S.pos>V;){let z=S.size;if(S.id==C&&z>=0){O.size=H,O.start=W,O.skip=K,K+=4,H+=4,S.next();continue}let X=S.pos-z;if(z<0||X=o?4:0,Se=S.start;for(S.next();S.pos>X;){if(S.size<0)if(S.size==-3||S.size==-4)Lt+=4;else break t;else S.id>=o&&(Lt+=4);S.next()}W=Se,H+=z,K+=Lt}return(C<0||H==T)&&(O.size=H,O.start=W,O.skip=K),O.size>4?O:void 0}function b(T,C,S){let{id:H,start:W,end:K,size:P}=l;if(l.next(),P>=0&&H4){let V=l.pos-(P-4);for(;l.pos>V;)S=b(T,C,S)}C[--S]=O,C[--S]=K-T,C[--S]=W-T,C[--S]=H}else P==-3?a=H:P==-4&&(f=H);return S}let y=[],v=[];for(;l.pos>0;)u(r.start||0,r.bufferStart||0,y,v,-1,0);let E=(t=r.length)!==null&&t!==void 0?t:y.length?v[0]+y[0].length:0;return new Q(h[r.topID],y.reverse(),v.reverse(),E)}const hn=new WeakMap;function ui(r,t){if(!r.isAnonymous||t instanceof $t||t.type!=r)return 1;let e=hn.get(t);if(e==null){e=1;for(let i of t.children){if(i.type!=r||!(i instanceof Q)){e=1;break}e+=ui(r,i)}hn.set(t,e)}return e}function Ks(r,t,e,i,s,n,o,l,h){let a=0;for(let p=i;p=f)break;C+=S}if(v==E+1){if(C>f){let S=p[E];d(S.children,S.positions,0,S.children.length,g[E]+y);continue}u.push(p[E])}else{let S=g[v-1]+p[v-1].length-T;u.push(Ks(r,p,g,E,v,T,S,null,h))}c.push(T+y-n)}}return d(t,e,i,s,0),(l||h)(u,c,o)}class Jt{constructor(t,e,i,s,n=!1,o=!1){this.from=t,this.to=e,this.tree=i,this.offset=s,this.open=(n?1:0)|(o?2:0)}get openStart(){return(this.open&1)>0}get openEnd(){return(this.open&2)>0}static addTree(t,e=[],i=!1){let s=[new Jt(0,t.length,t,0,!1,i)];for(let n of e)n.to>t.length&&s.push(n);return s}static applyChanges(t,e,i=128){if(!e.length)return t;let s=[],n=1,o=t.length?t[0]:null;for(let l=0,h=0,a=0;;l++){let f=l=i)for(;o&&o.from=c.from||u<=c.to||a){let d=Math.max(c.from,h)-a,p=Math.min(c.to,u)-a;c=d>=p?null:new Jt(d,p,c.tree,c.offset+a,l>0,!!f)}if(c&&s.push(c),o.to>u)break;o=nnew $i(s.from,s.to)):[new $i(0,0)]:[new $i(0,t.length)],this.createParse(t,e||[],i)}parse(t,e,i){let s=this.startParse(t,e,i);for(;;){let n=s.advance();if(n)return n}}}class No{constructor(t){this.string=t}get length(){return this.string.length}chunk(t){return this.string.slice(t)}get lineChunks(){return!1}read(t,e){return this.string.slice(t,e)}}new R({perNode:!0});var an={};class bi{constructor(t,e,i,s,n,o,l,h,a,f=0,u){this.p=t,this.stack=e,this.state=i,this.reducePos=s,this.pos=n,this.score=o,this.buffer=l,this.bufferBase=h,this.curContext=a,this.lookAhead=f,this.parent=u}toString(){return`[${this.stack.filter((t,e)=>e%3==0).concat(this.state)}]@${this.pos}${this.score?"!"+this.score:""}`}static start(t,e,i=0){let s=t.parser.context;return new bi(t,[],e,i,i,0,[],0,s?new fn(s,s.start):null,0,null)}get context(){return this.curContext?this.curContext.context:null}pushState(t,e){this.stack.push(this.state,e,this.bufferBase+this.buffer.length),this.state=t}reduce(t){var e;let i=t>>19,s=t&65535,{parser:n}=this.p,o=this.reducePos=2e3&&!(!((e=this.p.parser.nodeSet.types[s])===null||e===void 0)&&e.isAnonymous)&&(a==this.p.lastBigReductionStart?(this.p.bigReductionCount++,this.p.lastBigReductionSize=f):this.p.lastBigReductionSizeh;)this.stack.pop();this.reduceContext(s,a)}storeNode(t,e,i,s=4,n=!1){if(t==0&&(!this.stack.length||this.stack[this.stack.length-1]0&&this.buffer[o-4]==0&&this.buffer[o-1]>-1){if(e==i)return;if(this.buffer[o-2]>=e){this.buffer[o-2]=i;return}}}if(!n||this.pos==i)this.buffer.push(t,e,i,s);else{let o=this.buffer.length;if(o>0&&(this.buffer[o-4]!=0||this.buffer[o-1]<0)){let l=!1;for(let h=o;h>0&&this.buffer[h-2]>i;h-=4)if(this.buffer[h-1]>=0){l=!0;break}if(l)for(;o>0&&this.buffer[o-2]>i;)this.buffer[o]=this.buffer[o-4],this.buffer[o+1]=this.buffer[o-3],this.buffer[o+2]=this.buffer[o-2],this.buffer[o+3]=this.buffer[o-1],o-=4,s>4&&(s-=4)}this.buffer[o]=t,this.buffer[o+1]=e,this.buffer[o+2]=i,this.buffer[o+3]=s}}shift(t,e,i,s){if(t&131072)this.pushState(t&65535,this.pos);else if((t&262144)==0){let n=t,{parser:o}=this.p;this.pos=s;let l=o.stateFlag(n,1);!l&&(s>i||e<=o.maxNode)&&(this.reducePos=s),this.pushState(n,l?i:Math.min(i,this.reducePos)),this.shiftContext(e,i),e<=o.maxNode&&this.buffer.push(e,i,s,4)}else this.pos=s,this.shiftContext(e,i),e<=this.p.parser.maxNode&&this.buffer.push(e,i,s,4)}apply(t,e,i,s){t&65536?this.reduce(t):this.shift(t,e,i,s)}useNode(t,e){let i=this.p.reused.length-1;(i<0||this.p.reused[i]!=t)&&(this.p.reused.push(t),i++);let s=this.pos;this.reducePos=this.pos=s+t.length,this.pushState(e,s),this.buffer.push(i,s,this.reducePos,-1),this.curContext&&this.updateContext(this.curContext.tracker.reuse(this.curContext.context,t,this,this.p.stream.reset(this.pos-t.length)))}split(){let t=this,e=t.buffer.length;for(e&&t.buffer[e-4]==0&&(e-=4);e>0&&t.buffer[e-2]>t.reducePos;)e-=4;let i=t.buffer.slice(e),s=t.bufferBase+e;for(;t&&s==t.bufferBase;)t=t.parent;return new bi(this.p,this.stack.slice(),this.state,this.reducePos,this.pos,this.score,i,s,this.curContext,this.lookAhead,t)}recoverByDelete(t,e){let i=t<=this.p.parser.maxNode;i&&this.storeNode(t,this.pos,e,4),this.storeNode(0,this.pos,e,i?8:4),this.pos=this.reducePos=e,this.score-=190}canShift(t){for(let e=new Io(this);;){let i=this.p.parser.stateSlot(e.state,4)||this.p.parser.hasAction(e.state,t);if(i==0)return!1;if((i&65536)==0)return!0;e.reduce(i)}}recoverByInsert(t){if(this.stack.length>=300)return[];let e=this.p.parser.nextStates(this.state);if(e.length>8||this.stack.length>=120){let s=[];for(let n=0,o;nh&1&&l==o)||s.push(e[n],o)}e=s}let i=[];for(let s=0;s>19,s=e&65535,n=this.stack.length-i*3;if(n<0||t.getGoto(this.stack[n],s,!1)<0){let o=this.findForcedReduction();if(o==null)return!1;e=o}this.storeNode(0,this.pos,this.pos,4,!0),this.score-=100}return this.reducePos=this.pos,this.reduce(e),!0}findForcedReduction(){let{parser:t}=this.p,e=[],i=(s,n)=>{if(!e.includes(s))return e.push(s),t.allActions(s,o=>{if(!(o&393216))if(o&65536){let l=(o>>19)-n;if(l>1){let h=o&65535,a=this.stack.length-l*3;if(a>=0&&t.getGoto(this.stack[a],h,!1)>=0)return l<<19|65536|h}}else{let l=i(o,n+1);if(l!=null)return l}})};return i(this.state,0)}forceAll(){for(;!this.p.parser.stateFlag(this.state,2);)if(!this.forceReduce()){this.storeNode(0,this.pos,this.pos,4,!0);break}return this}get deadEnd(){if(this.stack.length!=3)return!1;let{parser:t}=this.p;return t.data[t.stateSlot(this.state,1)]==65535&&!t.stateSlot(this.state,4)}restart(){this.storeNode(0,this.pos,this.pos,4,!0),this.state=this.stack[0],this.stack.length=0}sameState(t){if(this.state!=t.state||this.stack.length!=t.stack.length)return!1;for(let e=0;e0&&this.emitLookAhead()}}class fn{constructor(t,e){this.tracker=t,this.context=e,this.hash=t.strict?t.hash(e):0}}class Io{constructor(t){this.start=t,this.state=t.state,this.stack=t.stack,this.base=this.stack.length}reduce(t){let e=t&65535,i=t>>19;i==0?(this.stack==this.start.stack&&(this.stack=this.stack.slice()),this.stack.push(this.state,0,0),this.base+=3):this.base-=(i-1)*3;let s=this.start.p.parser.getGoto(this.stack[this.base-3],e,!0);this.state=s}}class xi{constructor(t,e,i){this.stack=t,this.pos=e,this.index=i,this.buffer=t.buffer,this.index==0&&this.maybeNext()}static create(t,e=t.bufferBase+t.buffer.length){return new xi(t,e,e-t.bufferBase)}maybeNext(){let t=this.stack.parent;t!=null&&(this.index=this.stack.bufferBase-t.bufferBase,this.stack=t,this.buffer=t.buffer)}get id(){return this.buffer[this.index-4]}get start(){return this.buffer[this.index-3]}get end(){return this.buffer[this.index-2]}get size(){return this.buffer[this.index-1]}next(){this.index-=4,this.pos-=4,this.index==0&&this.maybeNext()}fork(){return new xi(this.stack,this.pos,this.index)}}function Xe(r,t=Uint16Array){if(typeof r!="string")return r;let e=null;for(let i=0,s=0;i=92&&o--,o>=34&&o--;let h=o-32;if(h>=46&&(h-=46,l=!0),n+=h,l)break;n*=46}e?e[s++]=n:e=new t(n)}return e}class ci{constructor(){this.start=-1,this.value=-1,this.end=-1,this.extended=-1,this.lookAhead=0,this.mask=0,this.context=0}}const un=new ci;class Lo{constructor(t,e){this.input=t,this.ranges=e,this.chunk="",this.chunkOff=0,this.chunk2="",this.chunk2Pos=0,this.next=-1,this.token=un,this.rangeIndex=0,this.pos=this.chunkPos=e[0].from,this.range=e[0],this.end=e[e.length-1].to,this.readNext()}resolveOffset(t,e){let i=this.range,s=this.rangeIndex,n=this.pos+t;for(;ni.to:n>=i.to;){if(s==this.ranges.length-1)return null;let o=this.ranges[++s];n+=o.from-i.to,i=o}return n}clipPos(t){if(t>=this.range.from&&tt)return Math.max(t,e.from);return this.end}peek(t){let e=this.chunkOff+t,i,s;if(e>=0&&e=this.chunk2Pos&&il.to&&(this.chunk2=this.chunk2.slice(0,l.to-i)),s=this.chunk2.charCodeAt(0)}}return i>=this.token.lookAhead&&(this.token.lookAhead=i+1),s}acceptToken(t,e=0){let i=e?this.resolveOffset(e,-1):this.pos;if(i==null||i=this.chunk2Pos&&this.posthis.range.to?t.slice(0,this.range.to-this.pos):t,this.chunkPos=this.pos,this.chunkOff=0}}readNext(){return this.chunkOff>=this.chunk.length&&(this.getChunk(),this.chunkOff==this.chunk.length)?this.next=-1:this.next=this.chunk.charCodeAt(this.chunkOff)}advance(t=1){for(this.chunkOff+=t;this.pos+t>=this.range.to;){if(this.rangeIndex==this.ranges.length-1)return this.setDone();t-=this.range.to-this.pos,this.range=this.ranges[++this.rangeIndex],this.pos=this.range.from}return this.pos+=t,this.pos>=this.token.lookAhead&&(this.token.lookAhead=this.pos+1),this.readNext()}setDone(){return this.pos=this.chunkPos=this.end,this.range=this.ranges[this.rangeIndex=this.ranges.length-1],this.chunk="",this.next=-1}reset(t,e){if(e?(this.token=e,e.start=t,e.lookAhead=t+1,e.value=e.extended=-1):this.token=un,this.pos!=t){if(this.pos=t,t==this.end)return this.setDone(),this;for(;t=this.range.to;)this.range=this.ranges[++this.rangeIndex];t>=this.chunkPos&&t=this.chunkPos&&e<=this.chunkPos+this.chunk.length)return this.chunk.slice(t-this.chunkPos,e-this.chunkPos);if(t>=this.chunk2Pos&&e<=this.chunk2Pos+this.chunk2.length)return this.chunk2.slice(t-this.chunk2Pos,e-this.chunk2Pos);if(t>=this.range.from&&e<=this.range.to)return this.input.read(t,e);let i="";for(let s of this.ranges){if(s.from>=e)break;s.to>t&&(i+=this.input.read(Math.max(s.from,t),Math.min(s.to,e)))}return i}}class le{constructor(t,e){this.data=t,this.id=e}token(t,e){let{parser:i}=e.p;Wo(this.data,t,e,this.id,i.data,i.tokenPrecTable)}}le.prototype.contextual=le.prototype.fallback=le.prototype.extend=!1;le.prototype.fallback=le.prototype.extend=!1;function Wo(r,t,e,i,s,n){let o=0,l=1<0){let p=r[d];if(h.allows(p)&&(t.token.value==-1||t.token.value==p||Fo(p,t.token.value,s,n))){t.acceptToken(p);break}}let f=t.next,u=0,c=r[o+2];if(t.next<0&&c>u&&r[a+c*3-3]==65535){o=r[a+c*3-1];continue t}for(;u>1,p=a+d+(d<<1),g=r[p],m=r[p+1]||65536;if(f=m)u=d+1;else{o=r[p+2],t.advance();continue t}}break}}function cn(r,t,e){for(let i=t,s;(s=r[i])!=65535;i++)if(s==e)return i-t;return-1}function Fo(r,t,e,i){let s=cn(e,i,t);return s<0||cn(e,i,r)t)&&!i.type.isError)return e<0?Math.max(0,Math.min(i.to-1,t-25)):Math.min(r.length,Math.max(i.from+1,t+25));if(e<0?i.prevSibling():i.nextSibling())break;if(!i.parent())return e<0?0:r.length}}class Ho{constructor(t,e){this.fragments=t,this.nodeSet=e,this.i=0,this.fragment=null,this.safeFrom=-1,this.safeTo=-1,this.trees=[],this.start=[],this.index=[],this.nextFragment()}nextFragment(){let t=this.fragment=this.i==this.fragments.length?null:this.fragments[this.i++];if(t){for(this.safeFrom=t.openStart?dn(t.tree,t.from+t.offset,1)-t.offset:t.from,this.safeTo=t.openEnd?dn(t.tree,t.to+t.offset,-1)-t.offset:t.to;this.trees.length;)this.trees.pop(),this.start.pop(),this.index.pop();this.trees.push(t.tree),this.start.push(-t.offset),this.index.push(0),this.nextStart=this.safeFrom}else this.nextStart=1e9}nodeAt(t){if(tt)return this.nextStart=o,null;if(n instanceof Q){if(o==t){if(o=Math.max(this.safeFrom,t)&&(this.trees.push(n),this.start.push(o),this.index.push(0))}else this.index[e]++,this.nextStart=o+n.length}}}class Vo{constructor(t,e){this.stream=e,this.tokens=[],this.mainToken=null,this.actions=[],this.tokens=t.tokenizers.map(i=>new ci)}getActions(t){let e=0,i=null,{parser:s}=t.p,{tokenizers:n}=s,o=s.stateSlot(t.state,3),l=t.curContext?t.curContext.hash:0,h=0;for(let a=0;au.end+25&&(h=Math.max(u.lookAhead,h)),u.value!=0)){let c=e;if(u.extended>-1&&(e=this.addActions(t,u.extended,u.end,e)),e=this.addActions(t,u.value,u.end,e),!f.extend&&(i=u,e>c))break}}for(;this.actions.length>e;)this.actions.pop();return h&&t.setLookAhead(h),!i&&t.pos==this.stream.end&&(i=new ci,i.value=t.p.parser.eofTerm,i.start=i.end=t.pos,e=this.addActions(t,i.value,i.end,e)),this.mainToken=i,this.actions}getMainToken(t){if(this.mainToken)return this.mainToken;let e=new ci,{pos:i,p:s}=t;return e.start=i,e.end=Math.min(i+1,s.stream.end),e.value=i==s.stream.end?s.parser.eofTerm:0,e}updateCachedToken(t,e,i){let s=this.stream.clipPos(i.pos);if(e.token(this.stream.reset(s,t),i),t.value>-1){let{parser:n}=i.p;for(let o=0;o=0&&i.p.parser.dialect.allows(l>>1)){(l&1)==0?t.value=l>>1:t.extended=l>>1;break}}}else t.value=0,t.end=this.stream.clipPos(s+1)}putAction(t,e,i,s){for(let n=0;nt.bufferLength*4?new Ho(i,t.nodeSet):null}get parsedPos(){return this.minStackPos}advance(){let t=this.stacks,e=this.minStackPos,i=this.stacks=[],s,n;if(this.bigReductionCount>300&&t.length==1){let[o]=t;for(;o.forceReduce()&&o.stack.length&&o.stack[o.stack.length-2]>=this.lastBigReductionStart;);this.bigReductionCount=this.lastBigReductionSize=0}for(let o=0;oe)i.push(l);else{if(this.advanceStack(l,i,t))continue;{s||(s=[],n=[]),s.push(l);let h=this.tokens.getMainToken(l);n.push(h.value,h.end)}}break}}if(!i.length){let o=s&&$o(s);if(o)return lt&&console.log("Finish with "+this.stackID(o)),this.stackToTree(o);if(this.parser.strict)throw lt&&s&&console.log("Stuck with token "+(this.tokens.mainToken?this.parser.getName(this.tokens.mainToken.value):"none")),new SyntaxError("No parse at "+e);this.recovering||(this.recovering=5)}if(this.recovering&&s){let o=this.stoppedAt!=null&&s[0].pos>this.stoppedAt?s[0]:this.runRecovery(s,n,i);if(o)return lt&&console.log("Force-finish "+this.stackID(o)),this.stackToTree(o.forceAll())}if(this.recovering){let o=this.recovering==1?1:this.recovering*3;if(i.length>o)for(i.sort((l,h)=>h.score-l.score);i.length>o;)i.pop();i.some(l=>l.reducePos>e)&&this.recovering--}else if(i.length>1){t:for(let o=0;o500&&a.buffer.length>500)if((l.score-a.score||l.buffer.length-a.buffer.length)>0)i.splice(h--,1);else{i.splice(o--,1);continue t}}}i.length>12&&(i.sort((o,l)=>l.score-o.score),i.splice(12,i.length-12))}this.minStackPos=i[0].pos;for(let o=1;o ":"";if(this.stoppedAt!=null&&s>this.stoppedAt)return t.forceReduce()?t:null;if(this.fragments){let a=t.curContext&&t.curContext.tracker.strict,f=a?t.curContext.hash:0;for(let u=this.fragments.nodeAt(s);u;){let c=this.parser.nodeSet.types[u.type.id]==u.type?n.getGoto(t.state,u.type.id):-1;if(c>-1&&u.length&&(!a||(u.prop(R.contextHash)||0)==f))return t.useNode(u,c),lt&&console.log(o+this.stackID(t)+` (via reuse of ${n.getName(u.type.id)})`),!0;if(!(u instanceof Q)||u.children.length==0||u.positions[0]>0)break;let d=u.children[0];if(d instanceof Q&&u.positions[0]==0)u=d;else break}}let l=n.stateSlot(t.state,4);if(l>0)return t.reduce(l),lt&&console.log(o+this.stackID(t)+` (via always-reduce ${n.getName(l&65535)})`),!0;if(t.stack.length>=8400)for(;t.stack.length>6e3&&t.forceReduce(););let h=this.tokens.getActions(t);for(let a=0;as?e.push(p):i.push(p)}return!1}advanceFully(t,e){let i=t.pos;for(;;){if(!this.advanceStack(t,null,null))return!1;if(t.pos>i)return pn(t,e),!0}}runRecovery(t,e,i){let s=null,n=!1;for(let o=0;o ":"";if(l.deadEnd&&(n||(n=!0,l.restart(),lt&&console.log(f+this.stackID(l)+" (restarted)"),this.advanceFully(l,i))))continue;let u=l.split(),c=f;for(let d=0;d<10&&u.forceReduce()&&(lt&&console.log(c+this.stackID(u)+" (via force-reduce)"),!this.advanceFully(u,i));d++)lt&&(c=this.stackID(u)+" -> ");for(let d of l.recoverByInsert(h))lt&&console.log(f+this.stackID(d)+" (via recover-insert)"),this.advanceFully(d,i);this.stream.end>l.pos?(a==l.pos&&(a++,h=0),l.recoverByDelete(h,a),lt&&console.log(f+this.stackID(l)+` (via recover-delete ${this.parser.getName(h)})`),pn(l,i)):(!s||s.scoret.topRules[l][1]),s=[];for(let l=0;l=0)n(f,h,l[a++]);else{let u=l[a+-f];for(let c=-f;c>0;c--)n(l[a++],h,u);a++}}}this.nodeSet=new Hs(e.map((l,h)=>ot.define({name:h>=this.minRepeatTerm?void 0:l,id:h,props:s[h],top:i.indexOf(h)>-1,error:h==0,skipped:t.skippedNodes&&t.skippedNodes.indexOf(h)>-1}))),t.propSources&&(this.nodeSet=this.nodeSet.extend(...t.propSources)),this.strict=!1,this.bufferLength=1024;let o=Xe(t.tokenData);this.context=t.context,this.specializerSpecs=t.specialized||[],this.specialized=new Uint16Array(this.specializerSpecs.length);for(let l=0;ltypeof l=="number"?new le(o,l):l),this.topRules=t.topRules,this.dialects=t.dialects||{},this.dynamicPrecedences=t.dynamicPrecedences||null,this.tokenPrecTable=t.tokenPrec,this.termNames=t.termNames||null,this.maxNode=this.nodeSet.types.length-1,this.dialect=this.parseDialect(),this.top=this.topRules[Object.keys(this.topRules)[0]]}createParse(t,e,i){let s=new zo(this,t,e,i);for(let n of this.wrappers)s=n(s,t,e,i);return s}getGoto(t,e,i=!1){let s=this.goto;if(e>=s[0])return-1;for(let n=s[e+1];;){let o=s[n++],l=o&1,h=s[n++];if(l&&i)return h;for(let a=n+(o>>1);n0}validAction(t,e){return!!this.allActions(t,i=>i==e?!0:null)}allActions(t,e){let i=this.stateSlot(t,4),s=i?e(i):void 0;for(let n=this.stateSlot(t,1);s==null;n+=3){if(this.data[n]==65535)if(this.data[n+1]==1)n=Dt(this.data,n+2);else break;s=e(Dt(this.data,n+1))}return s}nextStates(t){let e=[];for(let i=this.stateSlot(t,1);;i+=3){if(this.data[i]==65535)if(this.data[i+1]==1)i=Dt(this.data,i+2);else break;if((this.data[i+2]&1)==0){let s=this.data[i+1];e.some((n,o)=>o&1&&n==s)||e.push(this.data[i],s)}}return e}configure(t){let e=Object.assign(Object.create(wi.prototype),this);if(t.props&&(e.nodeSet=this.nodeSet.extend(...t.props)),t.top){let i=this.topRules[t.top];if(!i)throw new RangeError(`Invalid top rule name ${t.top}`);e.top=i}return t.tokenizers&&(e.tokenizers=this.tokenizers.map(i=>{let s=t.tokenizers.find(n=>n.from==i);return s?s.to:i})),t.specializers&&(e.specializers=this.specializers.slice(),e.specializerSpecs=this.specializerSpecs.map((i,s)=>{let n=t.specializers.find(l=>l.from==i.external);if(!n)return i;let o=Object.assign(Object.assign({},i),{external:n.to});return e.specializers[s]=gn(o),o})),t.contextTracker&&(e.context=t.contextTracker),t.dialect&&(e.dialect=this.parseDialect(t.dialect)),t.strict!=null&&(e.strict=t.strict),t.wrap&&(e.wrappers=e.wrappers.concat(t.wrap)),t.bufferLength!=null&&(e.bufferLength=t.bufferLength),e}hasWrappers(){return this.wrappers.length>0}getName(t){return this.termNames?this.termNames[t]:String(t<=this.maxNode&&this.nodeSet.types[t].name||t)}get eofTerm(){return this.maxNode+1}get topNode(){return this.nodeSet.types[this.top[1]]}dynamicPrecedence(t){let e=this.dynamicPrecedences;return e==null?0:e[t]||0}parseDialect(t){let e=Object.keys(this.dialects),i=e.map(()=>!1);if(t)for(let n of t.split(" ")){let o=e.indexOf(n);o>=0&&(i[o]=!0)}let s=null;for(let n=0;ni)&&e.p.parser.stateFlag(e.state,2)&&(!t||t.scorer.external(e,i)<<1|t}return r.get}let qo=0;class ut{constructor(t,e,i,s){this.name=t,this.set=e,this.base=i,this.modified=s,this.id=qo++}toString(){let{name:t}=this;for(let e of this.modified)e.name&&(t=`${e.name}(${t})`);return t}static define(t,e){let i=typeof t=="string"?t:"?";if(t instanceof ut&&(e=t),e?.base)throw new Error("Can not derive from a modified tag");let s=new ut(i,[],null,[]);if(s.set.push(s),e)for(let n of e.set)s.set.push(n);return s}static defineModifier(t){let e=new yi(t);return i=>i.modified.indexOf(e)>-1?i:yi.get(i.base||i,i.modified.concat(e).sort((s,n)=>s.id-n.id))}}let jo=0;class yi{constructor(t){this.name=t,this.instances=[],this.id=jo++}static get(t,e){if(!e.length)return t;let i=e[0].instances.find(l=>l.base==t&&Qo(e,l.modified));if(i)return i;let s=[],n=new ut(t.name,s,t,e);for(let l of e)l.instances.push(n);let o=Uo(e);for(let l of t.set)if(!l.modified.length)for(let h of o)s.push(yi.get(l,h));return n}}function Qo(r,t){return r.length==t.length&&r.every((e,i)=>e==t[i])}function Uo(r){let t=[[]];for(let e=0;ei.length-e.length)}function gr(r){let t=Object.create(null);for(let e in r){let i=r[e];Array.isArray(i)||(i=[i]);for(let s of e.split(" "))if(s){let n=[],o=2,l=s;for(let u=0;;){if(l=="..."&&u>0&&u+3==s.length){o=1;break}let c=/^"(?:[^"\\]|\\.)*?"|[^\/!]+/.exec(l);if(!c)throw new RangeError("Invalid path: "+s);if(n.push(c[0]=="*"?"":c[0][0]=='"'?JSON.parse(c[0]):c[0]),u+=c[0].length,u==s.length)break;let d=s[u++];if(u==s.length&&d=="!"){o=0;break}if(d!="/")throw new RangeError("Invalid path: "+s);l=s.slice(u)}let h=n.length-1,a=n[h];if(!a)throw new RangeError("Invalid path: "+s);let f=new ki(i,o,h>0?n.slice(0,h):null);t[a]=f.sort(t[a])}}return Go.add(t)}const Go=new R({combine(r,t){let e,i,s;for(;r||t;){if(!r||t&&r.depth>=t.depth?(s=t,t=t.next):(s=r,r=r.next),e&&e.mode==s.mode&&!s.context&&!e.context)continue;let n=new ki(s.tags,s.mode,s.context);e?e.next=n:i=n,e=n}return i}});class ki{constructor(t,e,i,s){this.tags=t,this.mode=e,this.context=i,this.next=s}get opaque(){return this.mode==0}get inherit(){return this.mode==1}sort(t){return!t||t.depth{let o=s;for(let l of n)for(let h of l.set){let a=e[h.id];if(a){o=o?o+" "+a:a;break}}return o},scope:i}}const x=ut.define,_e=x(),Wt=x(),mn=x(Wt),bn=x(Wt),Ft=x(),Je=x(Ft),ji=x(Ft),St=x(),Gt=x(St),wt=x(),yt=x(),hs=x(),ve=x(hs),Ze=x(),A={comment:_e,lineComment:x(_e),blockComment:x(_e),docComment:x(_e),name:Wt,variableName:x(Wt),typeName:mn,tagName:x(mn),propertyName:bn,attributeName:x(bn),className:x(Wt),labelName:x(Wt),namespace:x(Wt),macroName:x(Wt),literal:Ft,string:Je,docString:x(Je),character:x(Je),attributeValue:x(Je),number:ji,integer:x(ji),float:x(ji),bool:x(Ft),regexp:x(Ft),escape:x(Ft),color:x(Ft),url:x(Ft),keyword:wt,self:x(wt),null:x(wt),atom:x(wt),unit:x(wt),modifier:x(wt),operatorKeyword:x(wt),controlKeyword:x(wt),definitionKeyword:x(wt),moduleKeyword:x(wt),operator:yt,derefOperator:x(yt),arithmeticOperator:x(yt),logicOperator:x(yt),bitwiseOperator:x(yt),compareOperator:x(yt),updateOperator:x(yt),definitionOperator:x(yt),typeOperator:x(yt),controlOperator:x(yt),punctuation:hs,separator:x(hs),bracket:ve,angleBracket:x(ve),squareBracket:x(ve),paren:x(ve),brace:x(ve),content:St,heading:Gt,heading1:x(Gt),heading2:x(Gt),heading3:x(Gt),heading4:x(Gt),heading5:x(Gt),heading6:x(Gt),contentSeparator:x(St),list:x(St),quote:x(St),emphasis:x(St),strong:x(St),link:x(St),monospace:x(St),strikethrough:x(St),inserted:x(),deleted:x(),changed:x(),invalid:x(),meta:Ze,documentMeta:x(Ze),annotation:x(Ze),processingInstruction:x(Ze),definition:ut.defineModifier("definition"),constant:ut.defineModifier("constant"),function:ut.defineModifier("function"),standard:ut.defineModifier("standard"),local:ut.defineModifier("local"),special:ut.defineModifier("special")};for(let r in A){let t=A[r];t instanceof ut&&(t.name=r)}Yo([{tag:A.link,class:"tok-link"},{tag:A.heading,class:"tok-heading"},{tag:A.emphasis,class:"tok-emphasis"},{tag:A.strong,class:"tok-strong"},{tag:A.keyword,class:"tok-keyword"},{tag:A.atom,class:"tok-atom"},{tag:A.bool,class:"tok-bool"},{tag:A.url,class:"tok-url"},{tag:A.labelName,class:"tok-labelName"},{tag:A.inserted,class:"tok-inserted"},{tag:A.deleted,class:"tok-deleted"},{tag:A.literal,class:"tok-literal"},{tag:A.string,class:"tok-string"},{tag:A.number,class:"tok-number"},{tag:[A.regexp,A.escape,A.special(A.string)],class:"tok-string2"},{tag:A.variableName,class:"tok-variableName"},{tag:A.local(A.variableName),class:"tok-variableName tok-local"},{tag:A.definition(A.variableName),class:"tok-variableName tok-definition"},{tag:A.special(A.variableName),class:"tok-variableName2"},{tag:A.definition(A.propertyName),class:"tok-propertyName tok-definition"},{tag:A.typeName,class:"tok-typeName"},{tag:A.namespace,class:"tok-namespace"},{tag:A.className,class:"tok-className"},{tag:A.macroName,class:"tok-macroName"},{tag:A.propertyName,class:"tok-propertyName"},{tag:A.operator,class:"tok-operator"},{tag:A.comment,class:"tok-comment"},{tag:A.meta,class:"tok-meta"},{tag:A.invalid,class:"tok-invalid"},{tag:A.punctuation,class:"tok-punctuation"}]);const Xo=gr({String:A.string,Number:A.number,"True False":A.bool,PropertyName:A.propertyName,Null:A.null,", :":A.separator,"[ ]":A.squareBracket,"{ }":A.brace}),_o=wi.deserialize({version:14,states:"$bOVQPOOOOQO'#Cb'#CbOnQPO'#CeOvQPO'#ClOOQO'#Cr'#CrQOQPOOOOQO'#Cg'#CgO}QPO'#CfO!SQPO'#CtOOQO,59P,59PO![QPO,59PO!aQPO'#CuOOQO,59W,59WO!iQPO,59WOVQPO,59QOqQPO'#CmO!nQPO,59`OOQO1G.k1G.kOVQPO'#CnO!vQPO,59aOOQO1G.r1G.rOOQO1G.l1G.lOOQO,59X,59XOOQO-E6k-E6kOOQO,59Y,59YOOQO-E6l-E6l",stateData:"#O~OeOS~OQSORSOSSOTSOWQO_ROgPO~OVXOgUO~O^[O~PVO[^O~O]_OVhX~OVaO~O]bO^iX~O^dO~O]_OVha~O]bO^ia~O",goto:"!kjPPPPPPkPPkqwPPPPk{!RPPP!XP!e!hXSOR^bQWQRf_TVQ_Q`WRg`QcZRicQTOQZRQe^RhbRYQR]R",nodeNames:"⚠ JsonText True False Null Number String } { Object Property PropertyName : , ] [ Array",maxTerm:25,nodeProps:[["isolate",-2,6,11,""],["openedBy",7,"{",14,"["],["closedBy",8,"}",15,"]"]],propSources:[Xo],skippedNodes:[0],repeatNodeCount:2,tokenData:"(|~RaXY!WYZ!W]^!Wpq!Wrs!]|}$u}!O$z!Q!R%T!R![&c![!]&t!}#O&y#P#Q'O#Y#Z'T#b#c'r#h#i(Z#o#p(r#q#r(w~!]Oe~~!`Wpq!]qr!]rs!xs#O!]#O#P!}#P;'S!];'S;=`$o<%lO!]~!}Og~~#QXrs!]!P!Q!]#O#P!]#U#V!]#Y#Z!]#b#c!]#f#g!]#h#i!]#i#j#m~#pR!Q![#y!c!i#y#T#Z#y~#|R!Q![$V!c!i$V#T#Z$V~$YR!Q![$c!c!i$c#T#Z$c~$fR!Q![!]!c!i!]#T#Z!]~$rP;=`<%l!]~$zO]~~$}Q!Q!R%T!R![&c~%YRT~!O!P%c!g!h%w#X#Y%w~%fP!Q![%i~%nRT~!Q![%i!g!h%w#X#Y%w~%zR{|&T}!O&T!Q![&Z~&WP!Q![&Z~&`PT~!Q![&Z~&hST~!O!P%c!Q![&c!g!h%w#X#Y%w~&yO[~~'OO_~~'TO^~~'WP#T#U'Z~'^P#`#a'a~'dP#g#h'g~'jP#X#Y'm~'rOR~~'uP#i#j'x~'{P#`#a(O~(RP#`#a(U~(ZOS~~(^P#f#g(a~(dP#i#j(g~(jP#X#Y(m~(rOQ~~(wOW~~(|OV~",tokenizers:[0],topRules:{JsonText:[0,1]},tokenPrec:0});let as=[],mr=[];(()=>{let r="lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(t=>t?parseInt(t,36):1);for(let t=0,e=0;t>1;if(r=mr[i])t=i+1;else return!0;if(t==e)return!1}}function xn(r){return r>=127462&&r<=127487}const wn=8205;function Zo(r,t,e=!0,i=!0){return(e?br:tl)(r,t,i)}function br(r,t,e){if(t==r.length)return t;t&&xr(r.charCodeAt(t))&&wr(r.charCodeAt(t-1))&&t--;let i=Qi(r,t);for(t+=yn(i);t=0&&xn(Qi(r,o));)n++,o-=2;if(n%2==0)break;t+=2}else break}return t}function tl(r,t,e){for(;t>1;){let i=br(r,t-2,e);if(i=56320&&r<57344}function wr(r){return r>=55296&&r<56320}function yn(r){return r<65536?1:2}class B{lineAt(t){if(t<0||t>this.length)throw new RangeError(`Invalid position ${t} in document of length ${this.length}`);return this.lineInner(t,!1,1,0)}line(t){if(t<1||t>this.lines)throw new RangeError(`Invalid line number ${t} in ${this.lines}-line document`);return this.lineInner(t,!0,1,0)}replace(t,e,i){[t,e]=ce(this,t,e);let s=[];return this.decompose(0,t,s,2),i.length&&i.decompose(0,i.length,s,3),this.decompose(e,this.length,s,1),vt.from(s,this.length-(e-t)+i.length)}append(t){return this.replace(this.length,this.length,t)}slice(t,e=this.length){[t,e]=ce(this,t,e);let i=[];return this.decompose(t,e,i,0),vt.from(i,e-t)}eq(t){if(t==this)return!0;if(t.length!=this.length||t.lines!=this.lines)return!1;let e=this.scanIdentical(t,1),i=this.length-this.scanIdentical(t,-1),s=new Be(this),n=new Be(t);for(let o=e,l=e;;){if(s.next(o),n.next(o),o=0,s.lineBreak!=n.lineBreak||s.done!=n.done||s.value!=n.value)return!1;if(l+=s.value.length,s.done||l>=i)return!0}}iter(t=1){return new Be(this,t)}iterRange(t,e=this.length){return new yr(this,t,e)}iterLines(t,e){let i;if(t==null)i=this.iter();else{e==null&&(e=this.lines+1);let s=this.line(t).from;i=this.iterRange(s,Math.max(s,e==this.lines+1?this.length:e<=1?0:this.line(e-1).to))}return new kr(i)}toString(){return this.sliceString(0)}toJSON(){let t=[];return this.flatten(t),t}constructor(){}static of(t){if(t.length==0)throw new RangeError("A document must have at least one line");return t.length==1&&!t[0]?B.empty:t.length<=32?new j(t):vt.from(j.split(t,[]))}}class j extends B{constructor(t,e=el(t)){super(),this.text=t,this.length=e}get lines(){return this.text.length}get children(){return null}lineInner(t,e,i,s){for(let n=0;;n++){let o=this.text[n],l=s+o.length;if((e?i:l)>=t)return new il(s,l,i,o);s=l+1,i++}}decompose(t,e,i,s){let n=t<=0&&e>=this.length?this:new j(kn(this.text,t,e),Math.min(e,this.length)-Math.max(0,t));if(s&1){let o=i.pop(),l=di(n.text,o.text.slice(),0,n.length);if(l.length<=32)i.push(new j(l,o.length+n.length));else{let h=l.length>>1;i.push(new j(l.slice(0,h)),new j(l.slice(h)))}}else i.push(n)}replace(t,e,i){if(!(i instanceof j))return super.replace(t,e,i);[t,e]=ce(this,t,e);let s=di(this.text,di(i.text,kn(this.text,0,t)),e),n=this.length+i.length-(e-t);return s.length<=32?new j(s,n):vt.from(j.split(s,[]),n)}sliceString(t,e=this.length,i=` +`){[t,e]=ce(this,t,e);let s="";for(let n=0,o=0;n<=e&&ot&&o&&(s+=i),tn&&(s+=l.slice(Math.max(0,t-n),e-n)),n=h+1}return s}flatten(t){for(let e of this.text)t.push(e)}scanIdentical(){return 0}static split(t,e){let i=[],s=-1;for(let n of t)i.push(n),s+=n.length+1,i.length==32&&(e.push(new j(i,s)),i=[],s=-1);return s>-1&&e.push(new j(i,s)),e}}class vt extends B{constructor(t,e){super(),this.children=t,this.length=e,this.lines=0;for(let i of t)this.lines+=i.lines}lineInner(t,e,i,s){for(let n=0;;n++){let o=this.children[n],l=s+o.length,h=i+o.lines-1;if((e?h:l)>=t)return o.lineInner(t,e,i,s);s=l+1,i=h+1}}decompose(t,e,i,s){for(let n=0,o=0;o<=e&&n=o){let a=s&((o<=t?1:0)|(h>=e?2:0));o>=t&&h<=e&&!a?i.push(l):l.decompose(t-o,e-o,i,a)}o=h+1}}replace(t,e,i){if([t,e]=ce(this,t,e),i.lines=n&&e<=l){let h=o.replace(t-n,e-n,i),a=this.lines-o.lines+h.lines;if(h.lines>4&&h.lines>a>>6){let f=this.children.slice();return f[s]=h,new vt(f,this.length-(e-t)+i.length)}return super.replace(n,l,h)}n=l+1}return super.replace(t,e,i)}sliceString(t,e=this.length,i=` +`){[t,e]=ce(this,t,e);let s="";for(let n=0,o=0;nt&&n&&(s+=i),to&&(s+=l.sliceString(t-o,e-o,i)),o=h+1}return s}flatten(t){for(let e of this.children)e.flatten(t)}scanIdentical(t,e){if(!(t instanceof vt))return 0;let i=0,[s,n,o,l]=e>0?[0,0,this.children.length,t.children.length]:[this.children.length-1,t.children.length-1,-1,-1];for(;;s+=e,n+=e){if(s==o||n==l)return i;let h=this.children[s],a=t.children[n];if(h!=a)return i+h.scanIdentical(a,e);i+=h.length+1}}static from(t,e=t.reduce((i,s)=>i+s.length+1,-1)){let i=0;for(let d of t)i+=d.lines;if(i<32){let d=[];for(let p of t)p.flatten(d);return new j(d,e)}let s=Math.max(32,i>>5),n=s<<1,o=s>>1,l=[],h=0,a=-1,f=[];function u(d){let p;if(d.lines>n&&d instanceof vt)for(let g of d.children)u(g);else d.lines>o&&(h>o||!h)?(c(),l.push(d)):d instanceof j&&h&&(p=f[f.length-1])instanceof j&&d.lines+p.lines<=32?(h+=d.lines,a+=d.length+1,f[f.length-1]=new j(p.text.concat(d.text),p.length+1+d.length)):(h+d.lines>s&&c(),h+=d.lines,a+=d.length+1,f.push(d))}function c(){h!=0&&(l.push(f.length==1?f[0]:vt.from(f,a)),a=-1,h=f.length=0)}for(let d of t)u(d);return c(),l.length==1?l[0]:new vt(l,e)}}B.empty=new j([""],0);function el(r){let t=-1;for(let e of r)t+=e.length+1;return t}function di(r,t,e=0,i=1e9){for(let s=0,n=0,o=!0;n=e&&(h>i&&(l=l.slice(0,i-s)),s0?1:(t instanceof j?t.text.length:t.children.length)<<1]}nextInner(t,e){for(this.done=this.lineBreak=!1;;){let i=this.nodes.length-1,s=this.nodes[i],n=this.offsets[i],o=n>>1,l=s instanceof j?s.text.length:s.children.length;if(o==(e>0?l:0)){if(i==0)return this.done=!0,this.value="",this;e>0&&this.offsets[i-1]++,this.nodes.pop(),this.offsets.pop()}else if((n&1)==(e>0?0:1)){if(this.offsets[i]+=e,t==0)return this.lineBreak=!0,this.value=` +`,this;t--}else if(s instanceof j){let h=s.text[o+(e<0?-1:0)];if(this.offsets[i]+=e,h.length>Math.max(0,t))return this.value=t==0?h:e>0?h.slice(t):h.slice(0,h.length-t),this;t-=h.length}else{let h=s.children[o+(e<0?-1:0)];t>h.length?(t-=h.length,this.offsets[i]+=e):(e<0&&this.offsets[i]--,this.nodes.push(h),this.offsets.push(e>0?1:(h instanceof j?h.text.length:h.children.length)<<1))}}}next(t=0){return t<0&&(this.nextInner(-t,-this.dir),t=this.value.length),this.nextInner(t,this.dir)}}class yr{constructor(t,e,i){this.value="",this.done=!1,this.cursor=new Be(t,e>i?-1:1),this.pos=e>i?t.length:0,this.from=Math.min(e,i),this.to=Math.max(e,i)}nextInner(t,e){if(e<0?this.pos<=this.from:this.pos>=this.to)return this.value="",this.done=!0,this;t+=Math.max(0,e<0?this.pos-this.to:this.from-this.pos);let i=e<0?this.pos-this.from:this.to-this.pos;t>i&&(t=i),i-=t;let{value:s}=this.cursor.next(t);return this.pos+=(s.length+t)*e,this.value=s.length<=i?s:e<0?s.slice(s.length-i):s.slice(0,i),this.done=!this.value,this}next(t=0){return t<0?t=Math.max(t,this.from-this.pos):t>0&&(t=Math.min(t,this.to-this.pos)),this.nextInner(t,this.cursor.dir)}get lineBreak(){return this.cursor.lineBreak&&this.value!=""}}class kr{constructor(t){this.inner=t,this.afterBreak=!0,this.value="",this.done=!1}next(t=0){let{done:e,lineBreak:i,value:s}=this.inner.next(t);return e&&this.afterBreak?(this.value="",this.afterBreak=!1):e?(this.done=!0,this.value=""):i?this.afterBreak?this.value="":(this.afterBreak=!0,this.next()):(this.value=s,this.afterBreak=!1),this}get lineBreak(){return!1}}typeof Symbol<"u"&&(B.prototype[Symbol.iterator]=function(){return this.iter()},Be.prototype[Symbol.iterator]=yr.prototype[Symbol.iterator]=kr.prototype[Symbol.iterator]=function(){return this});class il{constructor(t,e,i,s){this.from=t,this.to=e,this.number=i,this.text=s}get length(){return this.to-this.from}}function ce(r,t,e){return t=Math.max(0,Math.min(r.length,t)),[t,Math.max(t,Math.min(r.length,e))]}function At(r,t,e=!0,i=!0){return Zo(r,t,e,i)}function sl(r){return r>=56320&&r<57344}function nl(r){return r>=55296&&r<56320}function rl(r,t){let e=r.charCodeAt(t);if(!nl(e)||t+1==r.length)return e;let i=r.charCodeAt(t+1);return sl(i)?(e-55296<<10)+(i-56320)+65536:e}function ol(r){return r<65536?1:2}const fs=/\r\n?|\n/;var at=(function(r){return r[r.Simple=0]="Simple",r[r.TrackDel=1]="TrackDel",r[r.TrackBefore=2]="TrackBefore",r[r.TrackAfter=3]="TrackAfter",r})(at||(at={}));class Et{constructor(t){this.sections=t}get length(){let t=0;for(let e=0;et)return n+(t-s);n+=l}else{if(i!=at.Simple&&a>=t&&(i==at.TrackDel&&st||i==at.TrackBefore&&st))return null;if(a>t||a==t&&e<0&&!l)return t==s||e<0?n:n+h;n+=h}s=a}if(t>s)throw new RangeError(`Position ${t} is out of range for changeset of length ${s}`);return n}touchesRange(t,e=t){for(let i=0,s=0;i=0&&s<=e&&l>=t)return se?"cover":!0;s=l}return!1}toString(){let t="";for(let e=0;e=0?":"+s:"")}return t}toJSON(){return this.sections}static fromJSON(t){if(!Array.isArray(t)||t.length%2||t.some(e=>typeof e!="number"))throw new RangeError("Invalid JSON representation of ChangeDesc");return new Et(t)}static create(t){return new Et(t)}}class Y extends Et{constructor(t,e){super(t),this.inserted=e}apply(t){if(this.length!=t.length)throw new RangeError("Applying change set to a document with the wrong length");return us(this,(e,i,s,n,o)=>t=t.replace(s,s+(i-e),o),!1),t}mapDesc(t,e=!1){return cs(this,t,e,!0)}invert(t){let e=this.sections.slice(),i=[];for(let s=0,n=0;s=0){e[s]=l,e[s+1]=o;let h=s>>1;for(;i.length0&&Kt(i,e,n.text),n.forward(f),l+=f}let a=t[o++];for(;l>1].toJSON()))}return t}static of(t,e,i){let s=[],n=[],o=0,l=null;function h(f=!1){if(!f&&!s.length)return;oc||u<0||c>e)throw new RangeError(`Invalid change range ${u} to ${c} (in doc of length ${e})`);let p=d?typeof d=="string"?B.of(d.split(i||fs)):d:B.empty,g=p.length;if(u==c&&g==0)return;uo&&Z(s,u-o,-1),Z(s,c-u,g),Kt(n,s,p),o=c}}return a(t),h(!l),l}static empty(t){return new Y(t?[t,-1]:[],[])}static fromJSON(t){if(!Array.isArray(t))throw new RangeError("Invalid JSON representation of ChangeSet");let e=[],i=[];for(let s=0;sl&&typeof o!="string"))throw new RangeError("Invalid JSON representation of ChangeSet");if(n.length==1)e.push(n[0],0);else{for(;i.length=0&&e<=0&&e==r[s+1]?r[s]+=t:s>=0&&t==0&&r[s]==0?r[s+1]+=e:i?(r[s]+=t,r[s+1]+=e):r.push(t,e)}function Kt(r,t,e){if(e.length==0)return;let i=t.length-2>>1;if(i>1])),!(e||o==r.sections.length||r.sections[o+1]<0);)l=r.sections[o++],h=r.sections[o++];t(s,a,n,f,u),s=a,n=f}}}function cs(r,t,e,i=!1){let s=[],n=i?[]:null,o=new We(r),l=new We(t);for(let h=-1;;){if(o.done&&l.len||l.done&&o.len)throw new Error("Mismatched change set lengths");if(o.ins==-1&&l.ins==-1){let a=Math.min(o.len,l.len);Z(s,a,-1),o.forward(a),l.forward(a)}else if(l.ins>=0&&(o.ins<0||h==o.i||o.off==0&&(l.len=0&&h=0){let a=0,f=o.len;for(;f;)if(l.ins==-1){let u=Math.min(f,l.len);a+=u,f-=u,l.forward(u)}else if(l.ins==0&&l.lenh||o.ins>=0&&o.len>h)&&(l||i.length>a),n.forward2(h),o.forward(h)}}}}class We{constructor(t){this.set=t,this.i=0,this.next()}next(){let{sections:t}=this.set;this.i>1;return e>=t.length?B.empty:t[e]}textBit(t){let{inserted:e}=this.set,i=this.i-2>>1;return i>=e.length&&!t?B.empty:e[i].slice(this.off,t==null?void 0:this.off+t)}forward(t){t==this.len?this.next():(this.len-=t,this.off+=t)}forward2(t){this.ins==-1?this.forward(t):t==this.ins?this.next():(this.ins-=t,this.off+=t)}}class Ht{constructor(t,e,i,s){this.from=t,this.to=e,this.flags=i,this.goalColumn=s}get anchor(){return this.flags&32?this.to:this.from}get head(){return this.flags&32?this.from:this.to}get empty(){return this.from==this.to}get assoc(){return this.flags&8?-1:this.flags&16?1:0}get undirectional(){return(this.flags&64)>0}get bidiLevel(){let t=this.flags&7;return t==7?null:t}map(t,e=-1){let i,s;return this.empty?i=s=t.mapPos(this.from,e):(i=t.mapPos(this.from,1),s=t.mapPos(this.to,-1)),i==this.from&&s==this.to?this:new Ht(i,s,this.flags,this.goalColumn)}extend(t,e=t,i=0){if(t<=this.anchor&&e>=this.anchor)return k.range(t,e,void 0,void 0,i);let s=Math.abs(t-this.anchor)>Math.abs(e-this.anchor)?t:e;return k.range(this.anchor,s,void 0,void 0,i)}eq(t,e=!1){return this.anchor==t.anchor&&this.head==t.head&&this.goalColumn==t.goalColumn&&(!e||!this.empty||this.assoc==t.assoc)}toJSON(){return{anchor:this.anchor,head:this.head}}static fromJSON(t){if(!t||typeof t.anchor!="number"||typeof t.head!="number")throw new RangeError("Invalid JSON representation for SelectionRange");return k.range(t.anchor,t.head)}static create(t,e,i,s){return new Ht(t,e,i,s)}}class k{constructor(t,e){this.ranges=t,this.mainIndex=e}map(t,e=-1){return t.empty?this:k.create(this.ranges.map(i=>i.map(t,e)),this.mainIndex)}eq(t,e=!1){if(this.ranges.length!=t.ranges.length||this.mainIndex!=t.mainIndex)return!1;for(let i=0;it.toJSON()),main:this.mainIndex}}static fromJSON(t){if(!t||!Array.isArray(t.ranges)||typeof t.main!="number"||t.main>=t.ranges.length)throw new RangeError("Invalid JSON representation for EditorSelection");return new k(t.ranges.map(e=>Ht.fromJSON(e)),t.main)}static single(t,e=t){return new k([k.range(t,e)],0)}static create(t,e=0){if(t.length==0)throw new RangeError("A selection needs at least one range");for(let i=0,s=0;ss.from-n.from),e=t.indexOf(i);for(let s=1;sn.head?k.range(h,l):k.range(l,h))}}return new k(t,e)}}function vr(r,t){for(let e of r.ranges)if(e.to>t)throw new RangeError("Selection points outside of document")}let $s=0;class M{constructor(t,e,i,s,n){this.combine=t,this.compareInput=e,this.compare=i,this.isStatic=s,this.id=$s++,this.default=t([]),this.extensions=typeof n=="function"?n(this):n}get reader(){return this}static define(t={}){return new M(t.combine||(e=>e),t.compareInput||((e,i)=>e===i),t.compare||(t.combine?(e,i)=>e===i:qs),!!t.static,t.enables)}of(t){return new pi([],this,0,t)}compute(t,e){if(this.isStatic)throw new Error("Can't compute a static facet");return new pi(t,this,1,e)}computeN(t,e){if(this.isStatic)throw new Error("Can't compute a static facet");return new pi(t,this,2,e)}from(t,e){return e||(e=i=>i),this.compute([t],i=>e(i.field(t)))}}function qs(r,t){return r==t||r.length==t.length&&r.every((e,i)=>e===t[i])}class pi{constructor(t,e,i,s){this.dependencies=t,this.facet=e,this.type=i,this.value=s,this.id=$s++}dynamicSlot(t){var e;let i=this.value,s=this.facet.compareInput,n=this.id,o=t[n]>>1,l=this.type==2,h=!1,a=!1,f=[];for(let u of this.dependencies)u=="doc"?h=!0:u=="selection"?a=!0:(((e=t[u.id])!==null&&e!==void 0?e:1)&1)==0&&f.push(t[u.id]);return{create(u){return u.values[o]=i(u),1},update(u,c){if(h&&c.docChanged||a&&(c.docChanged||c.selection)||ds(u,f)){let d=i(u);if(l?!Sn(d,u.values[o],s):!s(d,u.values[o]))return u.values[o]=d,1}return 0},reconfigure:(u,c)=>{let d,p=c.config.address[n];if(p!=null){let g=vi(c,p);if(this.dependencies.every(m=>m instanceof M?c.facet(m)===u.facet(m):m instanceof se?c.field(m,!1)==u.field(m,!1):!0)||(l?Sn(d=i(u),g,s):s(d=i(u),g)))return u.values[o]=g,0}else d=i(u);return u.values[o]=d,1}}}get extension(){return this}}function Sn(r,t,e){if(r.length!=t.length)return!1;for(let i=0;ir[h.id]),s=e.map(h=>h.type),n=i.filter(h=>!(h&1)),o=r[t.id]>>1;function l(h){let a=[];for(let f=0;fi===s),t);return t.provide&&(e.provides=t.provide(e)),e}create(t){let e=t.facet(ti).find(i=>i.field==this);return(e?.create||this.createF)(t)}slot(t){let e=t[this.id]>>1;return{create:i=>(i.values[e]=this.create(i),1),update:(i,s)=>{let n=i.values[e],o=this.updateF(n,s);return this.compareF(n,o)?0:(i.values[e]=o,1)},reconfigure:(i,s)=>{let n=i.facet(ti),o=s.facet(ti),l;return(l=n.find(h=>h.field==this))&&l!=o.find(h=>h.field==this)?(i.values[e]=l.create(i),1):s.config.address[this.id]!=null?(i.values[e]=s.field(this),0):(i.values[e]=this.create(i),1)}}}init(t){return[this,ti.of({field:this,create:t})]}get extension(){return this}}const Xt={lowest:4,low:3,default:2,high:1,highest:0};function Ce(r){return t=>new Ar(t,r)}const Cr={highest:Ce(Xt.highest),high:Ce(Xt.high),default:Ce(Xt.default),low:Ce(Xt.low),lowest:Ce(Xt.lowest)};class Ar{constructor(t,e){this.inner=t,this.prec=e}get extension(){return this}}class Li{of(t){return new ps(this,t)}reconfigure(t){return Li.reconfigure.of({compartment:this,extension:t})}get(t){return t.config.compartments.get(this)}}class ps{constructor(t,e){this.compartment=t,this.inner=e}get extension(){return this}}class Si{constructor(t,e,i,s,n,o){for(this.base=t,this.compartments=e,this.dynamicSlots=i,this.address=s,this.staticValues=n,this.facets=o,this.statusTemplate=[];this.statusTemplate.length>1]}static resolve(t,e,i){let s=[],n=Object.create(null),o=new Map;for(let c of hl(t,e,o))c instanceof se?s.push(c):(n[c.facet.id]||(n[c.facet.id]=[])).push(c);let l=Object.create(null),h=[],a=[];for(let c of s)l[c.id]=a.length<<1,a.push(d=>c.slot(d));let f=i?.config.facets;for(let c in n){let d=n[c],p=d[0].facet,g=f&&f[c]||[];if(d.every(m=>m.type==0))if(l[p.id]=h.length<<1|1,qs(g,d))h.push(i.facet(p));else{let m=p.combine(d.map(b=>b.value));h.push(i&&p.compare(m,i.facet(p))?i.facet(p):m)}else{for(let m of d)m.type==0?(l[m.id]=h.length<<1|1,h.push(m.value)):(l[m.id]=a.length<<1,a.push(b=>m.dynamicSlot(b)));l[p.id]=a.length<<1,a.push(m=>ll(m,p,d))}}let u=a.map(c=>c(l));return new Si(t,o,u,l,h,n)}}function hl(r,t,e){let i=[[],[],[],[],[]],s=new Map;function n(o,l){let h=s.get(o);if(h!=null){if(h<=l)return;let a=i[h].indexOf(o);a>-1&&i[h].splice(a,1),o instanceof ps&&e.delete(o.compartment)}if(s.set(o,l),Array.isArray(o))for(let a of o)n(a,l);else if(o instanceof ps){if(e.has(o.compartment))throw new RangeError("Duplicate use of compartment in extensions");let a=t.get(o.compartment)||o.inner;e.set(o.compartment,a),n(a,l)}else if(o instanceof Ar)n(o.inner,o.prec);else if(o instanceof se)i[l].push(o),o.provides&&n(o.provides,l);else if(o instanceof pi)i[l].push(o),o.facet.extensions&&n(o.facet.extensions,Xt.default);else{let a=o.extension;if(!a)throw new Error(`Unrecognized extension value in extension set (${o}).`);if(a==o)throw new Error(`Unrecognized extension value in extension set (${o}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`);n(a,l)}}return n(r,Xt.default),i.reduce((o,l)=>o.concat(l))}function Re(r,t){if(t&1)return 2;let e=t>>1,i=r.status[e];if(i==4)throw new Error("Cyclic dependency between fields and/or facets");if(i&2)return i;r.status[e]=4;let s=r.computeSlot(r,r.config.dynamicSlots[e]);return r.status[e]=2|s}function vi(r,t){return t&1?r.config.staticValues[t>>1]:r.values[t>>1]}const Or=M.define(),gs=M.define({combine:r=>r.some(t=>t),static:!0}),Tr=M.define({combine:r=>r.length?r[0]:void 0,static:!0}),Mr=M.define(),Pr=M.define(),Dr=M.define(),Br=M.define({combine:r=>r.length?r[0]:!1});class ke{constructor(t,e){this.type=t,this.value=e}static define(){return new al}}class al{of(t){return new ke(this,t)}}class fl{constructor(t){this.map=t}of(t){return new U(this,t)}}class U{constructor(t,e){this.type=t,this.value=e}map(t){let e=this.type.map(this.value,t);return e===void 0?void 0:e==this.value?this:new U(this.type,e)}is(t){return this.type==t}static define(t={}){return new fl(t.map||(e=>e))}static mapEffects(t,e){if(!t.length)return t;let i=[];for(let s of t){let n=s.map(e);n&&i.push(n)}return i}}U.reconfigure=U.define();U.appendConfig=U.define();class tt{constructor(t,e,i,s,n,o){this.startState=t,this.changes=e,this.selection=i,this.effects=s,this.annotations=n,this.scrollIntoView=o,this._doc=null,this._state=null,i&&vr(i,e.newLength),n.some(l=>l.type==tt.time)||(this.annotations=n.concat(tt.time.of(Date.now())))}static create(t,e,i,s,n,o){return new tt(t,e,i,s,n,o)}get newDoc(){return this._doc||(this._doc=this.changes.apply(this.startState.doc))}get newSelection(){return this.selection||this.startState.selection.map(this.changes)}get state(){return this._state||this.startState.applyTransaction(this),this._state}annotation(t){for(let e of this.annotations)if(e.type==t)return e.value}get docChanged(){return!this.changes.empty}get reconfigured(){return this.startState.config!=this.state.config}isUserEvent(t){let e=this.annotation(tt.userEvent);return!!(e&&(e==t||e.length>t.length&&e.slice(0,t.length)==t&&e[t.length]=="."))}}tt.time=ke.define();tt.userEvent=ke.define();tt.addToHistory=ke.define();tt.remote=ke.define();function ul(r,t){let e=[];for(let i=0,s=0;;){let n,o;if(i=r[i]))n=r[i++],o=r[i++];else if(s=0;s--){let n=i[s](r);n instanceof tt?r=n:Array.isArray(n)&&n.length==1&&n[0]instanceof tt?r=n[0]:r=Er(t,he(n),!1)}return r}function dl(r){let t=r.startState,e=t.facet(Dr),i=r;for(let s=e.length-1;s>=0;s--){let n=e[s](r);n&&Object.keys(n).length&&(i=Rr(i,ms(t,n,r.changes.newLength),!0))}return i==r?r:tt.create(t,r.changes,r.selection,i.effects,i.annotations,i.scrollIntoView)}const pl=[];function he(r){return r==null?pl:Array.isArray(r)?r:[r]}var Rt=(function(r){return r[r.Word=0]="Word",r[r.Space=1]="Space",r[r.Other=2]="Other",r})(Rt||(Rt={}));const gl=/[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/;let bs;try{bs=new RegExp("[\\p{Alphabetic}\\p{Number}_]","u")}catch{}function ml(r){if(bs)return bs.test(r);for(let t=0;t"€"&&(e.toUpperCase()!=e.toLowerCase()||gl.test(e)))return!0}return!1}function bl(r){return t=>{if(!/\S/.test(t))return Rt.Space;if(ml(t))return Rt.Word;for(let e=0;e-1)return Rt.Word;return Rt.Other}}class I{constructor(t,e,i,s,n,o){this.config=t,this.doc=e,this.selection=i,this.values=s,this.status=t.statusTemplate.slice(),this.computeSlot=n,o&&(o._state=this);for(let l=0;ls.set(a,h)),e=null),s.set(l.value.compartment,l.value.extension)):l.is(U.reconfigure)?(e=null,i=l.value):l.is(U.appendConfig)&&(e=null,i=he(i).concat(l.value));let n;e?n=t.startState.values.slice():(e=Si.resolve(i,s,this),n=new I(e,this.doc,this.selection,e.dynamicSlots.map(()=>null),(h,a)=>a.reconfigure(h,this),null).values);let o=t.startState.facet(gs)?t.newSelection:t.newSelection.asSingle();new I(e,t.newDoc,o,n,(l,h)=>h.update(l,t),t)}replaceSelection(t){return typeof t=="string"&&(t=this.toText(t)),this.changeByRange(e=>({changes:{from:e.from,to:e.to,insert:t},range:k.cursor(e.from+t.length)}))}changeByRange(t){let e=this.selection,i=t(e.ranges[0]),s=this.changes(i.changes),n=[i.range],o=he(i.effects);for(let l=1;lo.spec.fromJSON(l,h)))}}return I.create({doc:t.doc,selection:k.fromJSON(t.selection),extensions:e.extensions?s.concat([e.extensions]):s})}static create(t={}){let e=Si.resolve(t.extensions||[],new Map),i=t.doc instanceof B?t.doc:B.of((t.doc||"").split(e.staticFacet(I.lineSeparator)||fs)),s=t.selection?t.selection instanceof k?t.selection:k.single(t.selection.anchor,t.selection.head):k.single(0);return vr(s,i.length),e.staticFacet(gs)||(s=s.asSingle()),new I(e,i,s,e.dynamicSlots.map(()=>null),(n,o)=>o.create(n),null)}get tabSize(){return this.facet(I.tabSize)}get lineBreak(){return this.facet(I.lineSeparator)||` +`}get readOnly(){return this.facet(Br)}phrase(t,...e){for(let i of this.facet(I.phrases))if(Object.prototype.hasOwnProperty.call(i,t)){t=i[t];break}return e.length&&(t=t.replace(/\$(\$|\d*)/g,(i,s)=>{if(s=="$")return"$";let n=+(s||1);return!n||n>e.length?i:e[n-1]})),t}languageDataAt(t,e,i=-1){let s=[];for(let n of this.facet(Or))for(let o of n(this,e,i))Object.prototype.hasOwnProperty.call(o,t)&&s.push(o[t]);return s}charCategorizer(t){let e=this.languageDataAt("wordChars",t);return bl(e.length?e[0]:"")}wordAt(t){let{text:e,from:i,length:s}=this.doc.lineAt(t),n=this.charCategorizer(t),o=t-i,l=t-i;for(;o>0;){let h=At(e,o,!1);if(n(e.slice(h,o))!=Rt.Word)break;o=h}for(;lr.length?r[0]:4});I.lineSeparator=Tr;I.readOnly=Br;I.phrases=M.define({compare(r,t){let e=Object.keys(r),i=Object.keys(t);return e.length==i.length&&e.every(s=>r[s]==t[s])}});I.languageData=Or;I.changeFilter=Mr;I.transactionFilter=Pr;I.transactionExtender=Dr;Li.reconfigure=U.define();class Zt{eq(t){return this==t}range(t,e=t){return Fe.create(t,e,this)}}Zt.prototype.startSide=Zt.prototype.endSide=0;Zt.prototype.point=!1;Zt.prototype.mapMode=at.TrackDel;function js(r,t){return r==t||r.constructor==t.constructor&&r.eq(t)}class Fe{constructor(t,e,i){this.from=t,this.to=e,this.value=i}static create(t,e,i){return new Fe(t,e,i)}}function xs(r,t){return r.from-t.from||r.value.startSide-t.value.startSide}class Qs{constructor(t,e,i,s){this.from=t,this.to=e,this.value=i,this.maxPoint=s}get length(){return this.to[this.to.length-1]}findIndex(t,e,i,s=0){let n=i?this.to:this.from;for(let o=s,l=n.length;;){if(o==l)return o;let h=o+l>>1,a=n[h]-t||(i?this.value[h].endSide:this.value[h].startSide)-e;if(h==o)return a>=0?o:l;a>=0?l=h:o=h+1}}between(t,e,i,s){for(let n=this.findIndex(e,-1e9,!0),o=this.findIndex(i,1e9,!1,n);nd||c==d&&a.startSide>0&&a.endSide<=0)continue;(d-c||a.endSide-a.startSide)<0||(o<0&&(o=c),a.point&&(l=Math.max(l,d-c)),i.push(a),s.push(c-o),n.push(d-o))}return{mapped:i.length?new Qs(s,n,i,l):null,pos:o}}}class N{constructor(t,e,i,s){this.chunkPos=t,this.chunk=e,this.nextLayer=i,this.maxPoint=s}static create(t,e,i,s){return new N(t,e,i,s)}get length(){let t=this.chunk.length-1;return t<0?0:Math.max(this.chunkEnd(t),this.nextLayer.length)}get size(){if(this.isEmpty)return 0;let t=this.nextLayer.size;for(let e of this.chunk)t+=e.value.length;return t}chunkEnd(t){return this.chunkPos[t]+this.chunk[t].length}update(t){let{add:e=[],sort:i=!1,filterFrom:s=0,filterTo:n=this.length}=t,o=t.filter;if(e.length==0&&!o)return this;if(i&&(e=e.slice().sort(xs)),this.isEmpty)return e.length?N.of(e):this;let l=new Nr(this,null,-1).goto(0),h=0,a=[],f=new Ci;for(;l.value||h=0){let u=e[h++];f.addInner(u.from,u.to,u.value)||a.push(u)}else l.rangeIndex==1&&l.chunkIndexthis.chunkEnd(l.chunkIndex)||nl.to||n=n&&t<=n+o.length&&o.between(n,t-n,e-n,i)===!1)return}this.nextLayer.between(t,e,i)}}iter(t=0){return He.from([this]).goto(t)}get isEmpty(){return this.nextLayer==this}static iter(t,e=0){return He.from(t).goto(e)}static compare(t,e,i,s,n=-1){let o=t.filter(u=>u.maxPoint>0||!u.isEmpty&&u.maxPoint>=n),l=e.filter(u=>u.maxPoint>0||!u.isEmpty&&u.maxPoint>=n),h=vn(o,l,i),a=new Ae(o,h,n),f=new Ae(l,h,n);i.iterGaps((u,c,d)=>Cn(a,u,f,c,d,s)),i.empty&&i.length==0&&Cn(a,0,f,0,0,s)}static eq(t,e,i=0,s){s==null&&(s=999999999);let n=t.filter(f=>!f.isEmpty&&e.indexOf(f)<0),o=e.filter(f=>!f.isEmpty&&t.indexOf(f)<0);if(n.length!=o.length)return!1;if(!n.length)return!0;let l=vn(n,o),h=new Ae(n,l,0).goto(i),a=new Ae(o,l,0).goto(i);for(;;){if(h.to!=a.to||!ws(h.active,a.active)||h.point&&(!a.point||!js(h.point,a.point)))return!1;if(h.to>s)return!0;h.next(),a.next()}}static spans(t,e,i,s,n=-1){let o=new Ae(t,null,n).goto(e),l=e,h=o.openStart;for(;;){let a=Math.min(o.to,i);if(o.point){let f=o.activeForPoint(o.to),u=o.pointFroml&&(s.span(l,a,o.active,h),h=o.openEnd(a));if(o.to>i)return h+(o.point&&o.to>i?1:0);l=o.to,o.next()}}static of(t,e=!1){let i=new Ci;for(let s of t instanceof Fe?[t]:e?xl(t):t)i.add(s.from,s.to,s.value);return i.finish()}static join(t){if(!t.length)return N.empty;let e=t[t.length-1];for(let i=t.length-2;i>=0;i--)for(let s=t[i];s!=N.empty;s=s.nextLayer)e=new N(s.chunkPos,s.chunk,e,Math.max(s.maxPoint,e.maxPoint));return e}}N.empty=new N([],[],null,-1);function xl(r){if(r.length>1)for(let t=r[0],e=1;e0)return r.slice().sort(xs);t=i}return r}N.empty.nextLayer=N.empty;class Ci{finishChunk(t){this.chunks.push(new Qs(this.from,this.to,this.value,this.maxPoint)),this.chunkPos.push(this.chunkStart),this.chunkStart=-1,this.setMaxPoint=Math.max(this.setMaxPoint,this.maxPoint),this.maxPoint=-1,t&&(this.from=[],this.to=[],this.value=[])}constructor(){this.chunks=[],this.chunkPos=[],this.chunkStart=-1,this.last=null,this.lastFrom=-1e9,this.lastTo=-1e9,this.from=[],this.to=[],this.value=[],this.maxPoint=-1,this.setMaxPoint=-1,this.nextLayer=null}add(t,e,i){this.addInner(t,e,i)||(this.nextLayer||(this.nextLayer=new Ci)).add(t,e,i)}addInner(t,e,i){let s=t-this.lastTo||i.startSide-this.last.endSide;if(s<=0&&(t-this.lastFrom||i.startSide-this.last.startSide)<0)throw new Error("Ranges must be added sorted by `from` position and `startSide`");return s<0?!1:(this.from.length==250&&this.finishChunk(!0),this.chunkStart<0&&(this.chunkStart=t),this.from.push(t-this.chunkStart),this.to.push(e-this.chunkStart),this.last=i,this.lastFrom=t,this.lastTo=e,this.value.push(i),i.point&&(this.maxPoint=Math.max(this.maxPoint,e-t)),!0)}addChunk(t,e){if((t-this.lastTo||e.value[0].startSide-this.last.endSide)<0)return!1;this.from.length&&this.finishChunk(!0),this.setMaxPoint=Math.max(this.setMaxPoint,e.maxPoint),this.chunks.push(e),this.chunkPos.push(t);let i=e.value.length-1;return this.last=e.value[i],this.lastFrom=e.from[i]+t,this.lastTo=e.to[i]+t,!0}finish(){return this.finishInner(N.empty)}finishInner(t){if(this.from.length&&this.finishChunk(!1),this.chunks.length==0)return t;let e=N.create(this.chunkPos,this.chunks,this.nextLayer?this.nextLayer.finishInner(t):t,this.setMaxPoint);return this.from=null,e}}function vn(r,t,e){let i=new Map;for(let n of r)for(let o=0;o=this.minPoint)break}}setRangeIndex(t){if(t==this.layer.chunk[this.chunkIndex].value.length){if(this.chunkIndex++,this.skip)for(;this.chunkIndex=i&&s.push(new Nr(o,e,i,n));return s.length==1?s[0]:new He(s)}get startSide(){return this.value?this.value.startSide:0}goto(t,e=-1e9){for(let i of this.heap)i.goto(t,e);for(let i=this.heap.length>>1;i>=0;i--)Ui(this.heap,i);return this.next(),this}forward(t,e){for(let i of this.heap)i.forward(t,e);for(let i=this.heap.length>>1;i>=0;i--)Ui(this.heap,i);(this.to-t||this.value.endSide-e)<0&&this.next()}next(){if(this.heap.length==0)this.from=this.to=1e9,this.value=null,this.rank=-1;else{let t=this.heap[0];this.from=t.from,this.to=t.to,this.value=t.value,this.rank=t.rank,t.value&&t.next(),Ui(this.heap,0)}}}function Ui(r,t){for(let e=r[t];;){let i=(t<<1)+1;if(i>=r.length)break;let s=r[i];if(i+1=0&&(s=r[i+1],i++),e.compare(s)<0)break;r[i]=e,r[t]=s,t=i}}class Ae{constructor(t,e,i){this.minPoint=i,this.active=[],this.activeTo=[],this.activeRank=[],this.minActive=-1,this.point=null,this.pointFrom=0,this.pointRank=0,this.to=-1e9,this.endSide=0,this.openStart=-1,this.cursor=He.from(t,e,i)}goto(t,e=-1e9){return this.cursor.goto(t,e),this.active.length=this.activeTo.length=this.activeRank.length=0,this.minActive=-1,this.to=t,this.endSide=e,this.openStart=-1,this.next(),this}forward(t,e){for(;this.minActive>-1&&(this.activeTo[this.minActive]-t||this.active[this.minActive].endSide-e)<0;)this.removeActive(this.minActive);this.cursor.forward(t,e)}removeActive(t){ei(this.active,t),ei(this.activeTo,t),ei(this.activeRank,t),this.minActive=An(this.active,this.activeTo)}addActive(t){let e=0,{value:i,to:s,rank:n}=this.cursor;for(;e0;)e++;ii(this.active,e,i),ii(this.activeTo,e,s),ii(this.activeRank,e,n),t&&ii(t,e,this.cursor.from),this.minActive=An(this.active,this.activeTo)}next(){let t=this.to,e=this.point;this.point=null;let i=this.openStart<0?[]:null;for(;;){let s=this.minActive;if(s>-1&&(this.activeTo[s]-this.cursor.from||this.active[s].endSide-this.cursor.startSide)<0){if(this.activeTo[s]>t){this.to=this.activeTo[s],this.endSide=this.active[s].endSide;break}this.removeActive(s),i&&ei(i,s)}else if(this.cursor.value)if(this.cursor.from>t){this.to=this.cursor.from,this.endSide=this.cursor.startSide;break}else{let n=this.cursor.value;if(!n.point)this.addActive(i),this.cursor.next();else if(e&&this.cursor.to==this.to&&this.cursor.from=0&&i[s]=0&&!(this.activeRank[i]t||this.activeTo[i]==t&&this.active[i].endSide>=this.point.endSide)&&e.push(this.active[i]);return e.reverse()}openEnd(t){let e=0;for(let i=this.activeTo.length-1;i>=0&&this.activeTo[i]>t;i--)e++;return e}}function Cn(r,t,e,i,s,n){r.goto(t),e.goto(i);let o=i+s,l=i,h=i-t,a=!!n.boundChange;for(let f=!1;;){let u=r.to+h-e.to,c=u||r.endSide-e.endSide,d=c<0?r.to+h:e.to,p=Math.min(d,o);if(r.point||e.point?(r.point&&e.point&&js(r.point,e.point)&&ws(r.activeForPoint(r.to),e.activeForPoint(e.to))||n.comparePoint(l,p,r.point,e.point),f=!1):(f&&n.boundChange(l),p>l&&!ws(r.active,e.active)&&n.compareRange(l,p,r.active,e.active),a&&po)break;l=d,c<=0&&r.next(),c>=0&&e.next()}}function ws(r,t){if(r.length!=t.length)return!1;for(let e=0;e=t;i--)r[i+1]=r[i];r[t]=e}function An(r,t){let e=-1,i=1e9;for(let s=0;s=t)return s;if(s==r.length)break;n+=r.charCodeAt(s)==9?e-n%e:1,s=At(r,s)}return r.length}const ys="ͼ",On=typeof Symbol>"u"?"__"+ys:Symbol.for(ys),ks=typeof Symbol>"u"?"__styleSet"+Math.floor(Math.random()*1e8):Symbol("styleSet"),Tn=typeof globalThis<"u"?globalThis:typeof window<"u"?window:{};class de{constructor(t,e){this.rules=[];let{finish:i}=e||{};function s(o){return/^@/.test(o)?[o]:o.split(/,\s*/)}function n(o,l,h,a){let f=[],u=/^@(\w+)\b/.exec(o[0]),c=u&&u[1]=="keyframes";if(u&&l==null)return h.push(o[0]+";");for(let d in l){let p=l[d];if(/&/.test(d))n(d.split(/,\s*/).map(g=>o.map(m=>g.replace(/&/,m))).reduce((g,m)=>g.concat(m)),p,h);else if(p&&typeof p=="object"){if(!u)throw new RangeError("The value of a property ("+d+") should be a primitive value.");n(s(d),p,f,c)}else p!=null&&f.push(d.replace(/_.*/,"").replace(/[A-Z]/g,g=>"-"+g.toLowerCase())+": "+p+";")}(f.length||c)&&h.push((i&&!u&&!a?o.map(i):o).join(", ")+" {"+f.join(" ")+"}")}for(let o in t)n(s(o),t[o],this.rules)}getRules(){return this.rules.join(` +`)}static newName(){let t=Tn[On]||1;return Tn[On]=t+1,ys+t.toString(36)}static mount(t,e,i){let s=t[ks],n=i&&i.nonce;s?n&&s.setNonce(n):s=new yl(t,n),s.mount(Array.isArray(e)?e:[e],t)}}let Mn=new Map;class yl{constructor(t,e){let i=t.ownerDocument||t,s=i.defaultView;if(!t.head&&t.adoptedStyleSheets&&s.CSSStyleSheet){let n=Mn.get(i);if(n)return t[ks]=n;this.sheet=new s.CSSStyleSheet,Mn.set(i,this)}else this.styleTag=i.createElement("style"),e&&this.styleTag.setAttribute("nonce",e);this.modules=[],t[ks]=this}mount(t,e){let i=this.sheet,s=0,n=0;for(let o=0;o-1&&(this.modules.splice(h,1),n--,h=-1),h==-1){if(this.modules.splice(n++,0,l),i)for(let a=0;a",191:"?",192:"~",219:"{",220:"|",221:"}",222:'"'},kl=typeof navigator<"u"&&/Mac/.test(navigator.platform),Sl=typeof navigator<"u"&&/MSIE \d|Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(navigator.userAgent);for(var J=0;J<10;J++)qt[48+J]=qt[96+J]=String(J);for(var J=1;J<=24;J++)qt[J+111]="F"+J;for(var J=65;J<=90;J++)qt[J]=String.fromCharCode(J+32),Ve[J]=String.fromCharCode(J);for(var Gi in qt)Ve.hasOwnProperty(Gi)||(Ve[Gi]=qt[Gi]);function vl(r){var t=kl&&r.metaKey&&r.shiftKey&&!r.ctrlKey&&!r.altKey||Sl&&r.shiftKey&&r.key&&r.key.length==1||r.key=="Unidentified",e=!t&&r.key||(r.shiftKey?Ve:qt)[r.keyCode]||r.key||"Unidentified";return e=="Esc"&&(e="Escape"),e=="Del"&&(e="Delete"),e=="Left"&&(e="ArrowLeft"),e=="Up"&&(e="ArrowUp"),e=="Right"&&(e="ArrowRight"),e=="Down"&&(e="ArrowDown"),e}let it=typeof navigator<"u"?navigator:{userAgent:"",vendor:"",platform:""},Ss=typeof document<"u"?document:{documentElement:{style:{}}};const vs=/Edge\/(\d+)/.exec(it.userAgent),Ir=/MSIE \d/.test(it.userAgent),Cs=/Trident\/(?:[7-9]|\d{2,})\..*rv:(\d+)/.exec(it.userAgent),Wi=!!(Ir||Cs||vs),Pn=!Wi&&/gecko\/(\d+)/i.test(it.userAgent),Yi=!Wi&&/Chrome\/(\d+)/.exec(it.userAgent),Dn="webkitFontSmoothing"in Ss.documentElement.style,As=!Wi&&/Apple Computer/.test(it.vendor),Bn=As&&(/Mobile\/\w+/.test(it.userAgent)||it.maxTouchPoints>2);var w={mac:Bn||/Mac/.test(it.platform),windows:/Win/.test(it.platform),linux:/Linux|X11/.test(it.platform),ie:Wi,ie_version:Ir?Ss.documentMode||6:Cs?+Cs[1]:vs?+vs[1]:0,gecko:Pn,gecko_version:Pn?+(/Firefox\/(\d+)/.exec(it.userAgent)||[0,0])[1]:0,chrome:!!Yi,chrome_version:Yi?+Yi[1]:0,ios:Bn,android:/Android\b/.test(it.userAgent),webkit:Dn,webkit_version:Dn?+(/\bAppleWebKit\/(\d+)/.exec(it.userAgent)||[0,0])[1]:0,safari:As,safari_version:As?+(/\bVersion\/(\d+(\.\d+)?)/.exec(it.userAgent)||[0,0])[1]:0,tabSize:Ss.documentElement.style.tabSize!=null?"tab-size":"-moz-tab-size"};function Us(r,t){for(let e in r)e=="class"&&t.class?t.class+=" "+r.class:e=="style"&&t.style?t.style+=";"+r.style:t[e]=r[e];return t}const Ai=Object.create(null);function Gs(r,t,e){if(r==t)return!0;r||(r=Ai),t||(t=Ai);let i=Object.keys(r),s=Object.keys(t);if(i.length-0!=s.length-0)return!1;for(let n of i)if(n!=e&&(s.indexOf(n)==-1||r[n]!==t[n]))return!1;return!0}function Cl(r,t){for(let e=r.attributes.length-1;e>=0;e--){let i=r.attributes[e].name;t[i]==null&&r.removeAttribute(i)}for(let e in t){let i=t[e];e=="style"?r.style.cssText=i:r.getAttribute(e)!=i&&r.setAttribute(e,i)}}function Rn(r,t,e){let i=!1;if(t)for(let s in t)e&&s in e||(i=!0,s=="style"?r.style.cssText="":r.removeAttribute(s));if(e)for(let s in e)t&&t[s]==e[s]||(i=!0,s=="style"?r.style.cssText=e[s]:r.setAttribute(s,e[s]));return i}function Al(r){let t=Object.create(null);for(let e=0;e0?3e8:-4e8:e>0?1e8:-1e8,new te(t,e,e,i,t.widget||null,!1)}static replace(t){let e=!!t.block,i,s;if(t.isBlockGap)i=-5e8,s=4e8;else{let{start:n,end:o}=Lr(t,e);i=(n?e?-3e8:-1:5e8)-1,s=(o?e?2e8:1:-6e8)+1}return new te(t,i,s,e,t.widget||null,!0)}static line(t){return new je(t)}static set(t,e=!1){return N.of(t,e)}hasHeight(){return this.widget?this.widget.estimatedHeight>-1:!1}}et.none=N.empty;class qe extends et{constructor(t){let{start:e,end:i}=Lr(t);super(e?-1:5e8,i?1:-6e8,null,t),this.tagName=t.tagName||"span",this.attrs=t.class&&t.attributes?Us(t.attributes,{class:t.class}):t.class?{class:t.class}:t.attributes||Ai}eq(t){return this==t||t instanceof qe&&this.tagName==t.tagName&&Gs(this.attrs,t.attrs)}range(t,e=t){if(t>=e)throw new RangeError("Mark decorations may not be empty");return super.range(t,e)}}qe.prototype.point=!1;class je extends et{constructor(t){super(-2e8,-2e8,null,t)}eq(t){return t instanceof je&&this.spec.class==t.spec.class&&Gs(this.spec.attributes,t.spec.attributes)}range(t,e=t){if(e!=t)throw new RangeError("Line decoration ranges must be zero-length");return super.range(t,e)}}je.prototype.mapMode=at.TrackBefore;je.prototype.point=!0;class te extends et{constructor(t,e,i,s,n,o){super(e,i,n,t),this.block=s,this.isReplace=o,this.mapMode=s?e<=0?at.TrackBefore:at.TrackAfter:at.TrackDel}get type(){return this.startSide!=this.endSide?pt.WidgetRange:this.startSide<=0?pt.WidgetBefore:pt.WidgetAfter}get heightRelevant(){return this.block||!!this.widget&&(this.widget.estimatedHeight>=5||this.widget.lineBreaks>0)}eq(t){return t instanceof te&&Ol(this.widget,t.widget)&&this.block==t.block&&this.startSide==t.startSide&&this.endSide==t.endSide}range(t,e=t){if(this.isReplace&&(t>e||t==e&&this.startSide>0&&this.endSide<=0))throw new RangeError("Invalid range for replacement decoration");if(!this.isReplace&&e!=t)throw new RangeError("Widget decorations can only have zero-length ranges");return super.range(t,e)}}te.prototype.point=!0;function Lr(r,t=!1){let{inclusiveStart:e,inclusiveEnd:i}=r;return e==null&&(e=r.inclusive),i==null&&(i=r.inclusive),{start:e??t,end:i??t}}function Ol(r,t){return r==t||!!(r&&t&&r.compare(t))}function ae(r,t,e,i=0){let s=e.length-1;s>=0&&e[s]+i>=r?e[s]=Math.max(e[s],t):e.push(r,t)}class ze extends Zt{constructor(t,e,i){super(),this.tagName=t,this.attributes=e,this.rank=i}eq(t){return t==this||t instanceof ze&&this.tagName==t.tagName&&Gs(this.attributes,t.attributes)}static create(t){return new ze(t.tagName,t.attributes||Ai,t.rank==null?50:Math.max(0,Math.min(t.rank,100)))}static set(t,e=!1){return N.of(t,e)}}ze.prototype.startSide=ze.prototype.endSide=-1;function Ke(r){let t;return r.nodeType==11?t=r.getSelection?r:r.ownerDocument:t=r,t.getSelection()}function Os(r,t){return t?r==t||r.contains(t.nodeType!=1?t.parentNode:t):!1}function Ee(r,t){if(!t.anchorNode)return!1;try{return Os(r,t.anchorNode)}catch{return!1}}function gi(r){return r.nodeType==3?$e(r,0,r.nodeValue.length).getClientRects():r.nodeType==1?r.getClientRects():[]}function Ne(r,t,e,i){return e?En(r,t,e,i,-1)||En(r,t,e,i,1):!1}function jt(r){for(var t=0;;t++)if(r=r.previousSibling,!r)return t}function Oi(r){return r.nodeType==1&&/^(DIV|P|LI|UL|OL|BLOCKQUOTE|DD|DT|H\d|SECTION|PRE)$/.test(r.nodeName)}function En(r,t,e,i,s){for(;;){if(r==e&&t==i)return!0;if(t==(s<0?0:It(r))){if(r.nodeName=="DIV")return!1;let n=r.parentNode;if(!n||n.nodeType!=1)return!1;t=jt(r)+(s<0?0:1),r=n}else if(r.nodeType==1){if(r=r.childNodes[t+(s<0?-1:0)],r.nodeType==1&&r.contentEditable=="false")return!1;t=s<0?It(r):0}else return!1}}function It(r){return r.nodeType==3?r.nodeValue.length:r.childNodes.length}function Ti(r,t){let{left:e,right:i}=r;if(e==i)return r;let s=t?e:i;return{left:s,right:s,top:r.top,bottom:r.bottom}}function Tl(r){let t=r.visualViewport;return t?{left:0,right:t.width,top:0,bottom:t.height}:{left:0,right:r.innerWidth,top:0,bottom:r.innerHeight}}function Wr(r,t){let e=t.width/r.offsetWidth,i=t.height/r.offsetHeight;return(e>.995&&e<1.005||!isFinite(e)||Math.abs(t.width-r.offsetWidth)<1)&&(e=1),(i>.995&&i<1.005||!isFinite(i)||Math.abs(t.height-r.offsetHeight)<1)&&(i=1),{scaleX:e,scaleY:i}}function Ml(r,t,e,i,s,n,o,l){let h=r.ownerDocument,a=h.defaultView||window;for(let f=r,u=!1;f&&!u;)if(f.nodeType==1){let c,d=f==h.body,p=1,g=1;if(d)c=Tl(a);else{if(/^(fixed|sticky)$/.test(getComputedStyle(f).position)&&(u=!0),f.scrollHeight<=f.clientHeight&&f.scrollWidth<=f.clientWidth){f=f.assignedSlot||f.parentNode;continue}let y=f.getBoundingClientRect();({scaleX:p,scaleY:g}=Wr(f,y)),c={left:y.left,right:y.left+f.clientWidth*p,top:y.top,bottom:y.top+f.clientHeight*g}}let m=0,b=0;if(s=="nearest")t.top0&&t.bottom>c.bottom+b&&(b=t.bottom-c.bottom+o)):t.bottom>c.bottom-o&&(b=t.bottom-c.bottom+o,e<0&&t.top-b0&&t.right>c.right+m&&(m=t.right-c.right+n)):t.right>c.right-n&&(m=t.right-c.right+n,e<0&&t.leftc.bottom||t.leftc.right)&&(t={left:Math.max(t.left,c.left),right:Math.min(t.right,c.right),top:Math.max(t.top,c.top),bottom:Math.min(t.bottom,c.bottom)}),f=f.assignedSlot||f.parentNode}else if(f.nodeType==11)f=f.host;else break}function Fr(r,t=!0){let e=r.ownerDocument,i=null,s=null;for(let n=r.parentNode;n&&!(n==e.body||(!t||i)&&s);)if(n.nodeType==1)!s&&n.scrollHeight>n.clientHeight&&(s=n),t&&!i&&n.scrollWidth>n.clientWidth&&(i=n),n=n.assignedSlot||n.parentNode;else if(n.nodeType==11)n=n.host;else break;return{x:i,y:s}}class Pl{constructor(){this.anchorNode=null,this.anchorOffset=0,this.focusNode=null,this.focusOffset=0}eq(t){return this.anchorNode==t.anchorNode&&this.anchorOffset==t.anchorOffset&&this.focusNode==t.focusNode&&this.focusOffset==t.focusOffset}setRange(t){let{anchorNode:e,focusNode:i}=t;this.set(e,Math.min(t.anchorOffset,e?It(e):0),i,Math.min(t.focusOffset,i?It(i):0))}set(t,e,i,s){this.anchorNode=t,this.anchorOffset=e,this.focusNode=i,this.focusOffset=s}}let Yt=null;w.safari&&w.safari_version>=26&&(Yt=!1);function Hr(r){if(r.setActive)return r.setActive();if(Yt)return r.focus(Yt);let t=[];for(let e=r;e&&(t.push(e,e.scrollTop,e.scrollLeft),e!=e.ownerDocument);e=e.parentNode);if(r.focus(Yt==null?{get preventScroll(){return Yt={preventScroll:!0},!0}}:void 0),!Yt){Yt=!1;for(let e=0;eMath.max(0,r.document.documentElement.scrollHeight-r.innerHeight-4):r.scrollTop>Math.max(1,r.scrollHeight-r.clientHeight-4)}function zr(r,t){for(let e=r,i=t;;){if(e.nodeType==3&&i>0)return{node:e,offset:i};if(e.nodeType==1&&i>0){if(e.contentEditable=="false")return null;e=e.childNodes[i-1],i=It(e)}else if(e.parentNode&&!Oi(e))i=jt(e),e=e.parentNode;else return null}}function Kr(r,t){for(let e=r,i=t;;){if(e.nodeType==3&&i=e){if(l.level==i)return o;(n<0||(s!=0?s<0?l.frome:t[n].level>l.level))&&(n=o)}}if(n<0)throw new RangeError("Index out of range");return n}}function jr(r,t){if(r.length!=t.length)return!1;for(let e=0;e=0;g-=3)if(kt[g+1]==-d){let m=kt[g+2],b=m&2?s:m&4?m&1?n:s:0;b&&(L[u]=L[kt[g]]=b),l=g;break}}else{if(kt.length==189)break;kt[l++]=u,kt[l++]=c,kt[l++]=h}else if((p=L[u])==2||p==1){let g=p==s;h=g?0:1;for(let m=l-3;m>=0;m-=3){let b=kt[m+2];if(b&2)break;if(g)kt[m+2]|=2;else{if(b&4)break;kt[m+2]|=4}}}}}function Wl(r,t,e,i){for(let s=0,n=i;s<=e.length;s++){let o=s?e[s-1].to:r,l=sh;)p==m&&(p=e[--g].from,m=g?e[g-1].to:r),L[--p]=d;h=f}else n=a,h++}}}function Ms(r,t,e,i,s,n,o){let l=i%2?2:1;if(i%2==s%2)for(let h=t,a=0;hh&&o.push(new Ot(h,g.from,d));let m=g.direction==ee!=!(d%2);Ps(r,m?i+1:i,s,g.inner,g.from,g.to,o),h=g.to}p=g.to}else{if(p==e||(f?L[p]!=l:L[p]==l))break;p++}c?Ms(r,h,p,i+1,s,c,o):ht;){let f=!0,u=!1;if(!a||h>n[a-1].to){let g=L[h-1];g!=l&&(f=!1,u=g==16)}let c=!f&&l==1?[]:null,d=f?i:i+1,p=h;t:for(;;)if(a&&p==n[a-1].to){if(u)break t;let g=n[--a];if(!f)for(let m=g.from,b=a;;){if(m==t)break t;if(b&&n[b-1].to==m)m=n[--b].from;else{if(L[m-1]==l)break t;break}}if(c)c.push(g);else{g.toL.length;)L[L.length]=256;let i=[],s=t==ee?0:1;return Ps(r,s,s,e,0,r.length,i),i}function Qr(r){return[new Ot(0,r,0)]}let Ur="";function Hl(r,t,e,i,s){var n;let o=i.head-r.from,l=Ot.find(t,o,(n=i.bidiLevel)!==null&&n!==void 0?n:-1,i.assoc),h=t[l],a=h.side(s,e);if(o==a){let c=l+=s?1:-1;if(c<0||c>=t.length)return null;h=t[l=c],o=h.side(!s,e),a=h.side(s,e)}let f=At(r.text,o,h.forward(s,e));(fh.to)&&(f=a),Ur=r.text.slice(Math.min(o,f),Math.max(o,f));let u=l==(s?t.length-1:0)?null:t[l+(s?1:-1)];return u&&f==a&&u.level+(s?0:1)r.some(t=>t)}),zl=M.define({combine:r=>r.some(t=>t)}),eo=M.define();class ue{constructor(t,e,i,s,n,o=!1){this.range=t,this.y=e,this.x=i,this.yMargin=s,this.xMargin=n,this.isSnapshot=o}map(t){return t.empty?this:new ue(this.range.map(t),this.y,this.x,this.yMargin,this.xMargin,this.isSnapshot)}clip(t){return this.range.to<=t.doc.length?this:new ue(k.cursor(t.doc.length),this.y,this.x,this.yMargin,this.xMargin,this.isSnapshot)}}const si=U.define({map:(r,t)=>r.map(t)}),io=U.define();function Tt(r,t,e){let i=r.facet(_r);i.length?i[0](t):window.onerror&&window.onerror(String(t),e,void 0,void 0,t)||(e?console.error(e+":",t):console.error(t))}const Bt=M.define({combine:r=>r.length?r[0]:!0});let Kl=0;const oe=M.define({combine(r){return r.filter((t,e)=>{for(let i=0;i{let h=[];return o&&h.push(Hi.of(a=>{let f=a.plugin(l);return f?o(f):et.none})),n&&h.push(n(l)),h})}static fromClass(t,e){return pe.define((i,s)=>new t(i,s),e)}}class Xi{constructor(t){this.spec=t,this.mustUpdate=null,this.value=null}get plugin(){return this.spec&&this.spec.plugin}update(t){if(this.value){if(this.mustUpdate){let e=this.mustUpdate;if(this.mustUpdate=null,this.value.update)try{this.value.update(e)}catch(i){if(Tt(e.state,i,"CodeMirror plugin crashed"),this.value.destroy)try{this.value.destroy()}catch{}this.deactivate()}}}else if(this.spec)try{this.value=this.spec.plugin.create(t,this.spec.arg)}catch(e){Tt(t.state,e,"CodeMirror plugin crashed"),this.deactivate()}return this}destroy(t){var e;if(!((e=this.value)===null||e===void 0)&&e.destroy)try{this.value.destroy()}catch(i){Tt(t.state,i,"CodeMirror plugin crashed")}}deactivate(){this.spec=this.value=null}}const so=M.define(),Js=M.define(),Hi=M.define(),no=M.define(),Zs=M.define(),Qe=M.define(),ro=M.define();function In(r,t){let e=r.state.facet(ro);if(!e.length)return e;let i=e.map(n=>n instanceof Function?n(r):n),s=[];return N.spans(i,t.from,t.to,{point(){},span(n,o,l,h){let a=n-t.from,f=o-t.from,u=s;for(let c=l.length-1;c>=0;c--,h--){let d=l[c].spec.bidiIsolate,p;if(d==null&&(d=Vl(t.text,a,f)),h>0&&u.length&&(p=u[u.length-1]).to==a&&p.direction==d)p.to=f,u=p.inner;else{let g={from:a,to:f,direction:d,inner:[]};u.push(g),u=g.inner}}}}),s}const oo=M.define();function lo(r){let t=0,e=0,i=0,s=0;for(let n of r.state.facet(oo)){let o=n(r);o&&(o.left!=null&&(t=Math.max(t,o.left)),o.right!=null&&(e=Math.max(e,o.right)),o.top!=null&&(i=Math.max(i,o.top)),o.bottom!=null&&(s=Math.max(s,o.bottom)))}return{left:t,right:e,top:i,bottom:s}}const Te=M.define();class ct{constructor(t,e,i,s){this.fromA=t,this.toA=e,this.fromB=i,this.toB=s}join(t){return new ct(Math.min(this.fromA,t.fromA),Math.max(this.toA,t.toA),Math.min(this.fromB,t.fromB),Math.max(this.toB,t.toB))}addToSet(t){let e=t.length,i=this;for(;e>0;e--){let s=t[e-1];if(!(s.fromA>i.toA)){if(s.toAs.push(new ct(n,o,l,h))),this.changedRanges=s}static create(t,e,i){return new Mi(t,e,i)}get viewportChanged(){return(this.flags&4)>0}get viewportMoved(){return(this.flags&8)>0}get heightChanged(){return(this.flags&2)>0}get geometryChanged(){return this.docChanged||(this.flags&18)>0}get focusChanged(){return(this.flags&1)>0}get docChanged(){return!this.changes.empty}get selectionSet(){return this.transactions.some(t=>t.selection)}get empty(){return this.flags==0&&this.transactions.length==0}}const $l=[];class q{constructor(t,e,i=0){this.dom=t,this.length=e,this.flags=i,this.parent=null,t.cmTile=this}get breakAfter(){return this.flags&1}get children(){return $l}isWidget(){return!1}get isHidden(){return!1}isComposite(){return!1}isLine(){return!1}isText(){return!1}isBlock(){return!1}get domAttrs(){return null}sync(t){if(this.flags|=2,this.flags&4){this.flags&=-5;let e=this.domAttrs;e&&Cl(this.dom,e)}}toString(){return this.constructor.name+(this.children.length?`(${this.children})`:"")+(this.breakAfter?"#":"")}destroy(){this.parent=null}setDOM(t){this.dom=t,t.cmTile=this}get posAtStart(){return this.parent?this.parent.posBefore(this):0}get posAtEnd(){return this.posAtStart+this.length}posBefore(t,e=this.posAtStart){let i=e;for(let s of this.children){if(s==t)return i;i+=s.length+s.breakAfter}throw new RangeError("Invalid child in posBefore")}posAfter(t){return this.posBefore(t)+t.length}covers(t){return!0}coordsIn(t,e,i){return null}domPosFor(t,e){let i=jt(this.dom),s=this.length?t>0:e>0;return new mt(this.parent.dom,i+(s?1:0),t==0||t==this.length)}markDirty(t){this.flags&=-3,t&&(this.flags|=4),this.parent&&this.parent.flags&2&&this.parent.markDirty(!1)}get overrideDOMText(){return null}get root(){for(let t=this;t;t=t.parent)if(t instanceof zi)return t;return null}static get(t){return t.cmTile}}class Vi extends q{constructor(t){super(t,0),this._children=[]}isComposite(){return!0}get children(){return this._children}get lastChild(){return this.children.length?this.children[this.children.length-1]:null}append(t){this.children.push(t),t.parent=this}sync(t){if(this.flags&2)return;super.sync(t);let e=this.dom,i=null,s,n=t?.node==e?t:null,o=0;for(let l of this.children){if(l.sync(t),o+=l.length+l.breakAfter,s=i?i.nextSibling:e.firstChild,n&&s!=l.dom&&(n.written=!0),l.dom.parentNode==e)for(;s&&s!=l.dom;)s=Ln(s);else e.insertBefore(l.dom,s);i=l.dom}for(s=i?i.nextSibling:e.firstChild,n&&s&&(n.written=!0);s;)s=Ln(s);this.length=o}}function Ln(r){let t=r.nextSibling;return r.parentNode.removeChild(r),t}class zi extends Vi{constructor(t,e){super(e),this.view=t}owns(t){for(;t;t=t.parent)if(t==this)return!0;return!1}isBlock(){return!0}nearest(t){for(;;){if(!t)return null;let e=q.get(t);if(e&&this.owns(e))return e;t=t.parentNode}}blockTiles(t){for(let e=[],i=this,s=0,n=0;;)if(s==i.children.length){if(!e.length)return;i=i.parent,i.breakAfter&&n++,s=e.pop()}else{let o=i.children[s++];if(o instanceof Nt)e.push(s),i=o,s=0;else{let l=n+o.length,h=t(o,n);if(h!==void 0)return h;n=l+o.breakAfter}}}resolveBlock(t,e){let i,s=-1,n,o=-1;if(this.blockTiles((l,h)=>{let a=h+l.length;if(t>=h&&t<=a){if(l.isWidget()&&e>=-1&&e<=1){if(l.flags&32)return!0;l.flags&16&&(i=void 0)}(ht||t==h&&(e>1?l.length:l.covers(-1)))&&(!n||!l.isWidget()&&n.isWidget())&&(n=l,o=t-h)}}),!i&&!n)throw new Error("No tile at position "+t);return i&&e<0||!n?{tile:i,offset:s}:{tile:n,offset:o}}}class Nt extends Vi{constructor(t,e){super(t),this.wrapper=e}isBlock(){return!0}covers(t){return this.children.length?t<0?this.children[0].covers(-1):this.lastChild.covers(1):!1}get domAttrs(){return this.wrapper.attributes}static of(t,e){let i=new Nt(e||document.createElement(t.tagName),t);return e||(i.flags|=4),i}}class ge extends Vi{constructor(t,e){super(t),this.attrs=e}isLine(){return!0}static start(t,e,i){let s=new ge(e||document.createElement("div"),t);return(!e||!i)&&(s.flags|=4),s}get domAttrs(){return this.attrs}resolveInline(t,e,i){let s=null,n=-1,o=null,l=-1;function h(f,u){for(let c=0,d=0;c=u&&(p.isComposite()?h(p,u-d):(!o||o.isHidden&&(e>0&&!(o.flags&32)||i&&jl(o,p)))&&(g>u||p.flags&32&&e<=1)?(o=p,l=u-d):(d=-1)&&(s=p,n=u-d)),d=g}}h(this,t);let a=(e<0?s:o)||s||o;return a?{tile:a,offset:a==s?n:l}:null}coordsIn(t,e,i){let s=this.resolveInline(t,e,!0);return s?s.tile.coordsIn(Math.max(0,s.offset),e,i):ql(this)}domIn(t,e){let i=this.resolveInline(t,e);if(i){let{tile:s,offset:n}=i;if(this.dom.contains(s.dom))return s.isText()?new mt(s.dom,Math.min(s.dom.nodeValue.length,n)):s.domPosFor(n,s.flags&16?1:s.flags&32?-1:e);let o=i.tile.parent,l=!1;for(let h of o.children){if(l)return new mt(h.dom,0);h==i.tile&&(l=!0)}}return new mt(this.dom,0)}}function ql(r){let t=r.dom.lastChild;if(!t)return r.dom.getBoundingClientRect();let e=gi(t);return e[e.length-1]||null}function jl(r,t){let e=r.coordsIn(0,1),i=t.coordsIn(0,1);return e&&i&&i.tops&&(t=s);let n=t,o=t,l=0;t==0&&e<0||t==s&&e>=0?w.chrome||w.gecko||(t?(n--,l=1):o=0)?0:h.length-1];return w.safari&&!l&&a.width==0&&(a=Array.prototype.find.call(h,f=>f.width)||a),i==null?a:Ti(a,(l?l>0:e<0)==i)}static of(t,e){let i=new _t(e||document.createTextNode(t),t);return e||(i.flags|=2),i}}class ie extends q{constructor(t,e,i,s){super(t,e,s),this.widget=i}isWidget(){return!0}get isHidden(){return this.widget.isHidden}covers(t){return this.flags&48?!1:(this.flags&(t<0?64:128))>0}coordsIn(t,e){return this.coordsInWidget(t,e,!1)}coordsInWidget(t,e,i){let s=this.widget.coordsAt(this.dom,t,e);if(s)return s;if(i)return Ti(this.dom.getBoundingClientRect(),this.length?t==0:e<=0);{let n=this.dom.getClientRects(),o=null;if(!n.length)return null;let l=this.flags&16?!0:this.flags&32?!1:t>0;for(let h=l?n.length-1:0;o=n[h],!(t>0?h==0:h==n.length-1||o.top0==i)}}class Ql{constructor(t){this.index=0,this.beforeBreak=!1,this.parents=[],this.tile=t}advance(t,e,i){let{tile:s,index:n,beforeBreak:o,parents:l}=this;for(;t||e>0;)if(s.isComposite())if(o){if(!t)break;i&&i.break(),t--,o=!1}else if(n==s.children.length){if(!t&&!l.length)break;i&&i.leave(s),o=!!s.breakAfter,{tile:s,index:n}=l.pop(),n++}else{let h=s.children[n],a=h.breakAfter;(e>0?h.length<=t:h.length=0;l--){let h=e.marks[l],a=s.lastChild;if(a instanceof rt&&a.mark.eq(h.mark))a.dom!=h.dom&&a.setDOM(_i(h.dom)),s=a;else{if(this.cache.reused.get(h)){let u=q.get(h.dom);u&&u.setDOM(_i(h.dom))}let f=rt.of(h.mark,h.dom);s.append(f),s=f}this.cache.reused.set(h,2)}let n=q.get(t.text);n&&this.cache.reused.set(n,2);let o=new _t(t.text,t.text.nodeValue);o.flags|=8,this.pos=t.range.toB,s.append(o)}addInlineWidget(t,e,i){let s=this.afterWidget&&t.flags&48&&(this.afterWidget.flags&48)==(t.flags&48);s||this.flushBuffer();let n=this.ensureMarks(e,i);!s&&!(t.flags&16)&&n.append(this.getBuffer(1)),n.append(t),this.pos+=t.length,this.afterWidget=t}addMark(t,e,i){this.flushBuffer(),this.ensureMarks(e,i).append(t),this.pos+=t.length,this.afterWidget=null}addBlockWidget(t){this.getBlockPos().append(t),this.pos+=t.length,this.lastBlock=t,this.endLine()}continueWidget(t){let e=this.afterWidget||this.lastBlock;e.length+=t,this.pos+=t}addLineStart(t,e){var i;t||(t=ho);let s=ge.start(t,e||((i=this.cache.find(ge))===null||i===void 0?void 0:i.dom),!!e);this.getBlockPos().append(this.lastBlock=this.curLine=s)}addLine(t){this.getBlockPos().append(t),this.pos+=t.length,this.lastBlock=t,this.endLine()}addBreak(){this.lastBlock.flags|=1,this.endLine(),this.pos++}addLineStartIfNotCovered(t){this.blockPosCovered()||this.addLineStart(t)}ensureLine(t){this.curLine||this.addLineStart(t)}ensureMarks(t,e){var i;let s=this.curLine;for(let n=t.length-1;n>=0;n--){let o=t[n],l;if(e>0&&(l=s.lastChild)&&l instanceof rt&&l.mark.eq(o))s=l,e--;else{let h=rt.of(o,(i=this.cache.find(rt,a=>a.mark.eq(o)))===null||i===void 0?void 0:i.dom);s.append(h),s=h,e=0}}return s}endLine(){if(this.curLine){this.flushBuffer();let t=this.curLine.lastChild;(!t||!Wn(this.curLine,!1)||t.dom.nodeName!="BR"&&t.isWidget()&&!(w.ios&&Wn(this.curLine,!0)))&&this.curLine.append(this.cache.findWidget(Ji,0,32)||new ie(Ji.toDOM(),0,Ji,32)),this.curLine=this.afterWidget=null}}updateBlockWrappers(){this.wrapperPos>this.pos+1e4&&(this.blockWrappers.goto(this.pos),this.wrappers.length=0);for(let t=this.wrappers.length-1;t>=0;t--)this.wrappers[t].to=this.pos){let e=t.rank*102+t.value.rank,i=new Ul(t.from,t.to,t.value,e),s=this.wrappers.length;for(;s>0&&(this.wrappers[s-1].rank-i.rank||this.wrappers[s-1].to-i.to)<0;)s--;this.wrappers.splice(s,0,i)}this.wrapperPos=this.pos}getBlockPos(){var t;this.updateBlockWrappers();let e=this.root;for(let i of this.wrappers){let s=e.lastChild;if(i.fromo.wrapper.eq(i.wrapper)))===null||t===void 0?void 0:t.dom);e.append(n),e=n}}return e}blockPosCovered(){let t=this.lastBlock;return t!=null&&!t.breakAfter&&(!t.isWidget()||(t.flags&160)>0)}getBuffer(t){let e=2|(t<0?16:32),i=this.cache.find(Pi,void 0,1);return i&&(i.flags=e),i||new Pi(e)}flushBuffer(){this.afterWidget&&!(this.afterWidget.flags&32)&&(this.afterWidget.parent.append(this.getBuffer(-1)),this.afterWidget=null)}}class Yl{constructor(t){this.skipCount=0,this.text="",this.textOff=0,this.cursor=t.iter()}skip(t){this.textOff+t<=this.text.length?this.textOff+=t:(this.skipCount+=t-(this.text.length-this.textOff),this.text="",this.textOff=0)}next(t){if(this.textOff==this.text.length){let{value:s,lineBreak:n,done:o}=this.cursor.next(this.skipCount);if(this.skipCount=0,o)throw new Error("Ran out of text content when drawing inline views");this.text=s;let l=this.textOff=Math.min(t,s.length);return n?null:s.slice(0,l)}let e=Math.min(this.text.length,this.textOff+t),i=this.text.slice(this.textOff,e);return this.textOff=e,i}}const Di=[ie,ge,_t,rt,Pi,Nt,zi];for(let r=0;r[]),this.index=Di.map(()=>0),this.reused=new Map}add(t){let e=t.constructor.bucket,i=this.buckets[e];i.length<6?i.push(t):i[this.index[e]=(this.index[e]+1)%6]=t}find(t,e,i=2){let s=t.bucket,n=this.buckets[s],o=this.index[s];for(let l=0;l{if(this.cache.add(o),o.isComposite())return!1},enter:o=>this.cache.add(o),leave:()=>{},break:()=>{}}}run(t,e){let i=e&&this.getCompositionContext(e.text);for(let s=0,n=0,o=0;;){let l=os){let a=h-s;this.preserve(a,!o,!l),s=h,n+=a}if(!l)break;e&&l.fromA<=e.range.fromA&&l.toA>=e.range.toA?(this.forward(l.fromA,e.range.fromA,e.range.fromA{if(o.isWidget())if(this.openWidget)this.builder.continueWidget(h-l);else{let a=h>0||l{o.isLine()?this.builder.addLineStart(o.attrs,this.cache.maybeReuse(o)):(this.cache.add(o),o instanceof rt&&s.unshift(o.mark)),this.openWidget=!1},leave:o=>{o.isLine()?s.length&&(s.length=n=0):o instanceof rt&&(s.shift(),n=Math.min(n,s.length))},break:()=>{this.builder.addBreak(),this.openWidget=!1}}),this.text.skip(t)}emit(t,e){let i=null,s=this.builder,n=-1,o=N.spans(this.decorations,t,e,{point:(l,h,a,f,u,c)=>{if(a instanceof te){if(this.disallowBlockEffectsFor[c]){if(a.block)throw new RangeError("Block decorations may not be specified via plugins");if(h>this.view.state.doc.lineAt(l).to)throw new RangeError("Decorations that replace line breaks may not be specified via plugins")}if(n=f.length,u>f.length)s.continueWidget(h-l);else{let d=a.widget||(a.block?me.block:me.inline),p=Jl(a),g=this.cache.findWidget(d,h-l,p)||ie.of(d,this.view,h-l,p);a.block?(a.startSide>0&&s.addLineStartIfNotCovered(i),s.addBlockWidget(g)):(s.ensureLine(i),s.addInlineWidget(g,f,u))}i=null}else i=Zl(i,a);h>l&&this.text.skip(h-l)},span:(l,h,a,f)=>{for(let u=l;u-1&&(this.openWidget=o>n),this.openWidget||s.addLineStartIfNotCovered(i),this.openMarks=o}forward(t,e,i=1){e-t<=10?this.old.advance(e-t,i,this.reuseWalker):(this.old.advance(5,-1,this.reuseWalker),this.old.advance(e-t-10,-1),this.old.advance(5,i,this.reuseWalker))}getCompositionContext(t){let e=[],i=null;for(let s=t.parentNode;;s=s.parentNode){let n=q.get(s);if(s==this.view.contentDOM)break;n instanceof rt?e.push(n):n?.isLine()?i=n:n instanceof Nt||(s.nodeName=="DIV"&&!i&&s!=this.view.contentDOM?i=new ge(s,ho):i||e.push(rt.of(new qe({tagName:s.nodeName.toLowerCase(),attributes:Al(s)}),s)))}return{line:i,marks:e}}}function Wn(r,t){let e=i=>{for(let s of i.children)if((t?s.isText():s.length)||e(s))return!0;return!1};return e(r)}function Jl(r){let t=r.isReplace?(r.startSide<0?64:0)|(r.endSide>0?128:0):r.startSide>0?32:16;return r.block&&(t|=256),t}const ho={class:"cm-line"};function Zl(r,t){let e=t.spec.attributes,i=t.spec.class;return!e&&!i||(r||(r={class:"cm-line"}),e&&Us(e,r),i&&(r.class+=" "+i)),r}function th(r){let t=[];for(let e=r.parents.length;e>1;e--){let i=e==r.parents.length?r.tile:r.parents[e].tile;i instanceof rt&&t.push(i.mark)}return t}function _i(r){let t=q.get(r);return t&&t.setDOM(r.cloneNode()),r}class me extends Fi{constructor(t){super(),this.tag=t}eq(t){return t.tag==this.tag}toDOM(){return document.createElement(this.tag)}updateDOM(t){return t.nodeName.toLowerCase()==this.tag}get isHidden(){return!0}}me.inline=new me("span");me.block=new me("div");const Ji=new class extends Fi{toDOM(){return document.createElement("br")}get isHidden(){return!0}get editable(){return!0}};class Fn{constructor(t){this.view=t,this.decorations=[],this.blockWrappers=[],this.dynamicDecorationMap=[!1],this.domChanged=null,this.hasComposition=null,this.editContextFormatting=et.none,this.lastCompositionAfterCursor=!1,this.minWidth=0,this.minWidthFrom=0,this.minWidthTo=0,this.impreciseAnchor=null,this.impreciseHead=null,this.forceSelection=!1,this.lastUpdate=Date.now(),this.updateDeco(),this.tile=new zi(t,t.contentDOM),this.updateInner([new ct(0,0,0,t.state.doc.length)],null)}update(t){var e;let i=t.changedRanges;this.minWidth>0&&i.length&&(i.every(({fromA:f,toA:u})=>uthis.minWidthTo)?(this.minWidthFrom=t.changes.mapPos(this.minWidthFrom,1),this.minWidthTo=t.changes.mapPos(this.minWidthTo,1)):this.minWidth=this.minWidthFrom=this.minWidthTo=0),this.updateEditContextFormatting(t);let s=-1;this.view.inputState.composing>=0&&!this.view.observer.editContext&&(!((e=this.domChanged)===null||e===void 0)&&e.newSel?s=this.domChanged.newSel.head:!ah(t.changes,this.hasComposition)&&!t.selectionSet&&(s=t.state.selection.main.head));let n=s>-1?ih(this.view,t.changes,s):null;if(this.domChanged=null,this.hasComposition){let{from:f,to:u}=this.hasComposition;i=new ct(f,u,t.changes.mapPos(f,-1),t.changes.mapPos(u,1)).addToSet(i.slice())}this.hasComposition=n?{from:n.range.fromB,to:n.range.toB}:null,(w.ie||w.chrome)&&!n&&t&&t.state.doc.lines!=t.startState.doc.lines&&(this.forceSelection=!0);let o=this.decorations,l=this.blockWrappers;this.updateDeco();let h=rh(o,this.decorations,t.changes);h.length&&(i=ct.extendWithRanges(i,h));let a=lh(l,this.blockWrappers,t.changes);return a.length&&(i=ct.extendWithRanges(i,a)),n&&!i.some(f=>f.fromA<=n.range.fromA&&f.toA>=n.range.toA)&&(i=n.range.addToSet(i.slice())),this.tile.flags&2&&i.length==0?!1:(this.updateInner(i,n),t.transactions.length&&(this.lastUpdate=Date.now()),!0)}updateInner(t,e){this.view.viewState.mustMeasureContent=!0;let{observer:i}=this.view;i.ignore(()=>{if(e||t.length){let o=this.tile,l=new _l(this.view,o,this.blockWrappers,this.decorations,this.dynamicDecorationMap);e&&q.get(e.text)&&l.cache.reused.set(q.get(e.text),2),this.tile=l.run(t,e),Bs(o,l.cache.reused)}this.tile.dom.style.height=this.view.viewState.contentHeight/this.view.scaleY+"px",this.tile.dom.style.flexBasis=this.minWidth?this.minWidth+"px":"";let n=w.chrome||w.ios?{node:i.selectionRange.focusNode,written:!1}:void 0;this.tile.sync(n),n&&(n.written||i.selectionRange.focusNode!=n.node||!this.tile.dom.contains(n.node))&&(this.forceSelection=!0),this.tile.dom.style.height=""});let s=[];if(this.view.viewport.from||this.view.viewport.to-1)&&Ee(i,this.view.observer.selectionRange)&&!(s&&i.contains(s));if(!(n||e||o))return;let l=this.forceSelection;this.forceSelection=!1;let h=this.view.state.selection.main,a,f;if(h.empty?f=a=this.inlineDOMNearPos(h.anchor,h.assoc||1):(f=this.inlineDOMNearPos(h.head,h.head==h.from?1:-1),a=this.inlineDOMNearPos(h.anchor,h.anchor==h.from?1:-1)),w.gecko&&h.empty&&!this.hasComposition&&eh(a)){let c=document.createTextNode("");this.view.observer.ignore(()=>a.node.insertBefore(c,a.node.childNodes[a.offset]||null)),a=f=new mt(c,0),l=!0}let u=this.view.observer.selectionRange;(l||!u.focusNode||(!Ne(a.node,a.offset,u.anchorNode,u.anchorOffset)||!Ne(f.node,f.offset,u.focusNode,u.focusOffset))&&!this.suppressWidgetCursorChange(u,h))&&(this.view.observer.ignore(()=>{w.android&&w.chrome&&i.contains(u.focusNode)&&hh(u.focusNode,i)&&(i.blur(),i.focus({preventScroll:!0}));let c=Ke(this.view.root);if(c)if(h.empty){if(w.gecko){let d=sh(a.node,a.offset);if(d&&d!=3){let p=(d==1?zr:Kr)(a.node,a.offset);p&&(a=new mt(p.node,p.offset))}}c.collapse(a.node,a.offset),h.bidiLevel!=null&&c.caretBidiLevel!==void 0&&(c.caretBidiLevel=h.bidiLevel)}else if(c.extend){c.collapse(a.node,a.offset);try{c.extend(f.node,f.offset)}catch{}}else{let d=document.createRange();h.anchor>h.head&&([a,f]=[f,a]),d.setEnd(f.node,f.offset),d.setStart(a.node,a.offset),c.removeAllRanges(),c.addRange(d)}o&&this.view.root.activeElement==i&&(i.blur(),s&&s.focus())}),this.view.observer.setSelectionRange(a,f)),this.impreciseAnchor=a.precise?null:new mt(u.anchorNode,u.anchorOffset),this.impreciseHead=f.precise?null:new mt(u.focusNode,u.focusOffset)}suppressWidgetCursorChange(t,e){return this.hasComposition&&e.empty&&Ne(t.focusNode,t.focusOffset,t.anchorNode,t.anchorOffset)&&this.posFromDOM(t.focusNode,t.focusOffset)==e.head}enforceCursorAssoc(){if(this.hasComposition)return;let{view:t}=this,e=t.state.selection.main,i=Ke(t.root),{anchorNode:s,anchorOffset:n}=t.observer.selectionRange;if(!i||!e.empty||!e.assoc||!i.modify)return;let o=this.lineAt(e.head,e.assoc);if(!o)return;let l=o.posAtStart;if(e.head==l||e.head==l+o.length)return;let h=this.coordsAt(e.head,-1),a=this.coordsAt(e.head,1);if(!h||!a||h.bottom>a.top)return;let f=this.domAtPos(e.head+e.assoc,e.assoc);i.collapse(f.node,f.offset),i.modify("move",e.assoc<0?"forward":"backward","lineboundary"),t.observer.readSelectionRange();let u=t.observer.selectionRange;t.docView.posFromDOM(u.anchorNode,u.anchorOffset)!=e.from&&i.collapse(s,n)}posFromDOM(t,e){let i=this.tile.nearest(t);if(!i)return this.tile.dom.compareDocumentPosition(t)&2?0:this.view.state.doc.length;let s=i.posAtStart;if(i.isComposite()){let n;if(t==i.dom)n=i.dom.childNodes[e];else{let o=It(t)==0?0:e==0?-1:1;for(;;){let l=t.parentNode;if(l==i.dom)break;o==0&&l.firstChild!=l.lastChild&&(t==l.firstChild?o=-1:o=1),t=l}o<0?n=t:n=t.nextSibling}if(n==i.dom.firstChild)return s;for(;n&&!q.get(n);)n=n.nextSibling;if(!n)return s+i.length;for(let o=0,l=s;;o++){let h=i.children[o];if(h.dom==n)return l;l+=h.length+h.breakAfter}}else return i.isText()?t==i.dom?s+e:s+(e?i.length:0):s}domAtPos(t,e){let{tile:i,offset:s}=this.tile.resolveBlock(t,e);return i.isWidget()?i.domPosFor(s,e):i.domIn(s,e)}inlineDOMNearPos(t,e){let i,s=-1,n=!1,o,l=-1,h=!1;return this.tile.blockTiles((a,f)=>{if(a.isWidget()){if(a.flags&32&&f>=t)return!0;a.flags&16&&(n=!0)}else{let u=f+a.length;if(f<=t&&(i=a,s=t-f,n=u=t&&!o&&(o=a,l=t-f,h=f>t),f>t&&o)return!0}}),!i&&!o?this.domAtPos(t,e):(n&&o?i=null:h&&i&&(o=null),i&&e<0||!o?i.domIn(s,e):o.domIn(l,e))}coordsAt(t,e,i){let{tile:s,offset:n}=this.tile.resolveBlock(t,e);return s.isWidget()?s.widget instanceof Zi?null:s.coordsInWidget(n,e,!0):s.coordsIn(n,e,i)}lineAt(t,e){let{tile:i}=this.tile.resolveBlock(t,e);return i.isLine()?i:null}coordsForChar(t){let{tile:e,offset:i}=this.tile.resolveBlock(t,1);if(!e.isLine())return null;function s(n,o){if(n.isComposite())for(let l of n.children){if(l.length>=o){let h=s(l,o);if(h)return h}if(o-=l.length,o<0)break}else if(n.isText()&&oMath.max(this.view.scrollDOM.clientWidth,this.minWidth)+1,l=-1,h=this.view.textDirection==G.LTR,a=0,f=(u,c,d)=>{for(let p=0;ps);p++){let g=u.children[p],m=c+g.length,b=g.dom.getBoundingClientRect(),{height:y}=b;if(d&&!p&&(a+=b.top-d.top),g instanceof Nt)m>i&&f(g,c,b);else if(c>=i&&(a>0&&e.push(-a),e.push(y+a),a=0,o)){let v=g.dom.lastChild,E=v?gi(v):[];if(E.length){let T=E[E.length-1],C=h?T.right-b.left:b.right-T.left;C>l&&(l=C,this.minWidth=n,this.minWidthFrom=c,this.minWidthTo=m)}}d&&p==u.children.length-1&&(a+=d.bottom-b.bottom),c=m+g.breakAfter}};return f(this.tile,0,null),e}textDirectionAt(t){let{tile:e}=this.tile.resolveBlock(t,1);return getComputedStyle(e.dom).direction=="rtl"?G.RTL:G.LTR}measureTextSize(){let t=this.tile.blockTiles(o=>{if(o.isLine()&&o.children.length&&o.length<=20){let l=0,h;for(let a of o.children){if(!a.isText()||/[^ -~]/.test(a.text))return;let f=gi(a.dom);if(f.length!=1)return;l+=f[0].width,h=f[0].height}if(l)return{lineHeight:o.dom.getBoundingClientRect().height,charWidth:l/o.length,textHeight:h}}});if(t)return t;let e=document.createElement("div"),i,s,n;return e.className="cm-line",e.style.width="99999px",e.style.position="absolute",e.textContent="abc def ghi jkl mno pqr stu",this.view.observer.ignore(()=>{this.tile.dom.appendChild(e);let o=gi(e.firstChild)[0];i=e.getBoundingClientRect().height,s=o&&o.width?o.width/27:7,n=o&&o.height?o.height:i,e.remove()}),{lineHeight:i,charWidth:s,textHeight:n}}computeBlockGapDeco(){let t=[],e=this.view.viewState;for(let i=0,s=0;;s++){let n=s==e.viewports.length?null:e.viewports[s],o=n?n.from-1:this.view.state.doc.length;if(o>i){let l=(e.lineBlockAt(o).bottom-e.lineBlockAt(i).top)/this.view.scaleY;t.push(et.replace({widget:new Zi(l),block:!0,inclusive:!0,isBlockGap:!0}).range(i,o))}if(!n)break;i=n.to+1}return et.set(t)}updateDeco(){let t=1,e=this.view.state.facet(Hi).map(n=>(this.dynamicDecorationMap[t++]=typeof n=="function")?n(this.view):n),i=!1,s=this.view.state.facet(Zs).map((n,o)=>{let l=typeof n=="function";return l&&(i=!0),l?n(this.view):n});for(s.length&&(this.dynamicDecorationMap[t++]=i,e.push(N.join(s))),this.decorations=[this.editContextFormatting,...e,this.computeBlockGapDeco(),this.view.viewState.lineGapDeco];ttypeof n=="function"?n(this.view):n)}scrollIntoView(t){if(t.isSnapshot){let a=this.view.viewState.lineBlockAt(t.range.head);this.view.scrollDOM.scrollTop=a.top-t.yMargin,this.view.scrollDOM.scrollLeft=t.xMargin;return}for(let a of this.view.state.facet(eo))try{if(a(this.view,t.range,t))return!0}catch(f){Tt(this.view.state,f,"scroll handler")}let{range:e}=t,i=this.coordsAt(e.head,e.assoc||(e.head>e.anchor?-1:1)),s;if(!i)return;!e.empty&&(s=this.coordsAt(e.anchor,e.anchor>e.head?-1:1))&&(i={left:Math.min(i.left,s.left),top:Math.min(i.top,s.top),right:Math.max(i.right,s.right),bottom:Math.max(i.bottom,s.bottom)});let n=lo(this.view),o={left:i.left-n.left,top:i.top-n.top,right:i.right+n.right,bottom:i.bottom+n.bottom},{offsetWidth:l,offsetHeight:h}=this.view.scrollDOM;if(Ml(this.view.scrollDOM,o,e.head1&&(i.top>window.pageYOffset+window.visualViewport.offsetTop+window.visualViewport.height||i.bottomi.isWidget()||i.children.some(e);return e(this.tile.resolveBlock(t,1).tile)}destroy(){Bs(this.tile)}}function Bs(r,t){let e=t?.get(r);if(e!=1){e==null&&r.destroy();for(let i of r.children)Bs(i,t)}}function eh(r){return r.node.nodeType==1&&r.node.firstChild&&(r.offset==0||r.node.childNodes[r.offset-1].contentEditable=="false")&&(r.offset==r.node.childNodes.length||r.node.childNodes[r.offset].contentEditable=="false")}function ao(r,t){let e=r.observer.selectionRange;if(!e.focusNode)return null;let i=zr(e.focusNode,e.focusOffset),s=Kr(e.focusNode,e.focusOffset),n=i||s;if(s&&i&&s.node!=i.node){let l=q.get(s.node);if(!l||l.isText()&&l.text!=s.node.nodeValue)n=s;else if(r.docView.lastCompositionAfterCursor){let h=q.get(i.node);!h||h.isText()&&h.text!=i.node.nodeValue||(n=s)}}if(r.docView.lastCompositionAfterCursor=n!=i,!n)return null;let o=t-n.offset;return{from:o,to:o+n.node.nodeValue.length,node:n.node}}function ih(r,t,e){let i=ao(r,e);if(!i)return null;let{node:s,from:n,to:o}=i,l=s.nodeValue;if(/[\n\r]/.test(l)||r.state.doc.sliceString(i.from,i.to)!=l)return null;let h=t.invertedDesc;return{range:new ct(h.mapPos(n),h.mapPos(o),n,o),text:s}}function sh(r,t){return r.nodeType!=1?0:(t&&r.childNodes[t-1].contentEditable=="false"?1:0)|(t{it.from&&(e=!0)}),e}class Zi extends Fi{constructor(t){super(),this.height=t}toDOM(){let t=document.createElement("div");return t.className="cm-gap",this.updateDOM(t),t}eq(t){return t.height==this.height}updateDOM(t){return t.style.height=this.height+"px",!0}get editable(){return!0}get estimatedHeight(){return this.height}ignoreEvent(){return!1}}function fh(r,t,e=1){let i=r.charCategorizer(t),s=r.doc.lineAt(t),n=t-s.from;if(s.length==0)return k.cursor(t);n==0?e=1:n==s.length&&(e=-1);let o=n,l=n;e<0?o=At(s.text,n,!1):l=At(s.text,n);let h=i(s.text.slice(o,l));for(;o>0;){let a=At(s.text,o,!1);if(i(s.text.slice(a,o))!=h)break;o=a}for(;lr.defaultLineHeight*1.5){let l=r.viewState.heightOracle.textHeight,h=Math.floor((s-e.top-(r.defaultLineHeight-l)*.5)/l);n+=h*r.viewState.heightOracle.lineLength}let o=r.state.sliceDoc(e.from,e.to);return e.from+wl(o,n,r.state.tabSize)}function ch(r,t,e){let i=r.lineBlockAt(t);if(Array.isArray(i.type)){let s;for(let n of i.type){if(n.from>t)break;if(!(n.tot)return n;(!s||n.type==pt.Text&&(s.type!=n.type||(e<0?n.fromt)))&&(s=n)}}return s||i}return i}function dh(r,t,e,i){let s=ch(r,t.head,t.assoc||-1),n=!i||s.type!=pt.Text||!(r.lineWrapping||s.widgetLineBreaks)?null:r.coordsAtPos(t.assoc<0&&t.head>s.from?t.head-1:t.head);if(n){let o=r.dom.getBoundingClientRect(),l=r.textDirectionAt(s.from),h=r.posAtCoords({x:e==(l==G.LTR)?o.right-1:o.left+1,y:(n.top+n.bottom)/2});if(h!=null)return k.cursor(h,e?-1:1)}return k.cursor(e?s.to:s.from,e?-1:1)}function Hn(r,t,e,i){let s=r.state.doc.lineAt(t.head),n=r.bidiSpans(s),o=r.textDirectionAt(s.from);for(let l=t,h=null;;){let a=Hl(s,n,o,l,e),f=Ur;if(!a){if(s.number==(e?r.state.doc.lines:1))return l;f=` +`,s=r.state.doc.line(s.number+(e?1:-1)),n=r.bidiSpans(s),a=r.visualLineSide(s,!e)}if(h){if(!h(f))return l}else{if(!i)return a;h=i(f)}l=a}}function ph(r,t,e){let i=r.state.charCategorizer(t),s=i(e);return n=>{let o=i(n);return s==Rt.Space&&(s=o),s==o}}function gh(r,t,e,i){let s=t.head,n=e?1:-1;if(s==(e?r.state.doc.length:0))return k.cursor(s,t.assoc);let o=t.goalColumn,l,h=r.contentDOM.getBoundingClientRect(),a=r.coordsAtPos(s,t.assoc||((t.empty?e:t.head==t.from)?1:-1)),f=r.documentTop;if(a)o==null&&(o=a.left-h.left),l=n<0?a.top:a.bottom;else{let p=r.viewState.lineBlockAt(s);o==null&&(o=Math.min(h.right-h.left,r.defaultCharacterWidth*(s-p.from))),l=(n<0?p.top:p.bottom)+f}let u=h.left+o,c=r.viewState.heightOracle.textHeight>>1,d=i??c;for(let p=0;;p+=c){let g=l+(d+p)*n,m=Rs(r,{x:u,y:g},!1,n);if(e?g>h.bottom:gl:y{if(t>n&&ts(r)),e.from,t.head>e.from?-1:1);return i==e.from?e:k.cursor(i,ir.viewState.docHeight)return new Ct(r.state.doc.length,-1);if(a=r.elementAtHeight(h),i==null)break;if(a.type==pt.Text){if(i<0?a.tor.viewport.to)break;let c=r.docView.coordsAt(i<0?a.from:a.to,i>0?-1:1);if(c&&(i<0?c.top<=h+n:c.bottom>=h+n))break}let u=r.viewState.heightOracle.textHeight/2;h=i>0?a.bottom+u:a.top-u}if(r.viewport.from>=a.to||r.viewport.to<=a.from){if(e)return null;if(a.type==pt.Text){let u=uh(r,s,a,o,l);return new Ct(u,u==a.from?1:-1)}}if(a.type!=pt.Text)return h<(a.top+a.bottom)/2?new Ct(a.from,1):new Ct(a.to,-1);let f=r.docView.lineAt(a.from,2);return(!f||f.length!=a.length)&&(f=r.docView.lineAt(a.from,-2)),new mh(r,o,l,r.textDirectionAt(a.from)).scanTile(f,a.from)}class mh{constructor(t,e,i,s){this.view=t,this.x=e,this.y=i,this.baseDir=s,this.line=null,this.spans=null}bidiSpansAt(t){return(!this.line||this.line.from>t||this.line.to1||i.length&&(i[0].level!=this.baseDir||i[0].to+s.from>1;e:if(o.has(g)){let b=s+Math.floor(Math.random()*p);for(let y=0;y1)){if(y.bottomthis.y)(!a||a.top>y.top)&&(a=y),v=-1;else{let E=y.left>this.x?this.x-y.left:y.right(p+p+g)/3)return this.y=h.bottom-1,this.scan(t,e,!0);if(a&&a.top<(p+g+g)/3)return this.y=a.top+1,this.scan(t,e,!0)}let d=(l?this.dirAt(t[f],1):this.baseDir)==G.LTR;return{i:f,after:this.x>(c.left+c.right)/2==d}}scanText(t,e){let i=[];for(let n=0;n{let o=i[n]-e,l=i[n+1]-e;return $e(t.dom,o,l).getClientRects()});return s.after?new Ct(i[s.i+1],-1):new Ct(i[s.i],1)}scanTile(t,e){if(!t.length)return new Ct(e,1);if(t.children.length==1){let l=t.children[0];if(l.isText())return this.scanText(l,e);if(l.isComposite())return this.scanTile(l,e)}let i=[e];for(let l=0,h=e;l{let h=t.children[l];return h.flags&48?null:(h.dom.nodeType==1?h.dom:$e(h.dom,0,h.length)).getClientRects()}),n=t.children[s.i],o=i[s.i];return n.isText()?this.scanText(n,o):n.isComposite()?this.scanTile(n,o):s.after?new Ct(i[s.i+1],-1):new Ct(o,1)}}const re="￿";class bh{constructor(t,e){this.points=t,this.view=e,this.text="",this.lineSeparator=e.state.facet(I.lineSeparator)}append(t){this.text+=t}lineBreak(){this.text+=re}readRange(t,e){if(!t)return this;let i=t.parentNode;for(let s=t;;){this.findPointBefore(i,s);let n=this.text.length;this.readNode(s);let o=q.get(s),l=s.nextSibling;if(l==e){o?.breakAfter&&!l&&i!=this.view.contentDOM&&this.lineBreak();break}let h=q.get(l);(o&&h?o.breakAfter:(o?o.breakAfter:Oi(s))||Oi(l)&&(s.nodeName!="BR"||o?.isWidget())&&this.text.length>n)&&!wh(l,e)&&this.lineBreak(),s=l}return this.findPointBefore(i,e),this}readTextNode(t){let e=t.nodeValue;for(let i of this.points)i.node==t&&(i.pos=this.text.length+Math.min(i.offset,e.length));for(let i=0,s=this.lineSeparator?null:/\r\n?|\n/g;;){let n=-1,o=1,l;if(this.lineSeparator?(n=e.indexOf(this.lineSeparator,i),o=this.lineSeparator.length):(l=s.exec(e))&&(n=l.index,o=l[0].length),this.append(e.slice(i,n<0?e.length:n)),n<0)break;if(this.lineBreak(),o>1)for(let h of this.points)h.node==t&&h.pos>this.text.length&&(h.pos-=o-1);i=n+o}}readNode(t){let e=q.get(t),i=e&&e.overrideDOMText;if(i!=null){this.findPointInside(t,i.length);for(let s=i.iter();!s.next().done;)s.lineBreak?this.lineBreak():this.append(s.value)}else t.nodeType==3?this.readTextNode(t):t.nodeName=="BR"?t.nextSibling&&this.lineBreak():t.nodeType==1&&this.readRange(t.firstChild,null)}findPointBefore(t,e){for(let i of this.points)i.node==t&&t.childNodes[i.offset]==e&&(i.pos=this.text.length)}findPointInside(t,e){for(let i of this.points)(t.nodeType==3?i.node==t:t.contains(i.node))&&(i.pos=this.text.length+(xh(t,i.node,i.offset)?e:0))}}function xh(r,t,e){for(;;){if(!t||e-1;let{impreciseHead:n,impreciseAnchor:o}=t.docView,l=t.state.selection;if(t.state.readOnly&&e>-1)this.newSel=null;else if(e>-1&&(this.bounds=uo(t.docView.tile,e,i,0))){let h=n||o?[]:Sh(t),a=new bh(h,t);a.readRange(this.bounds.startDOM,this.bounds.endDOM),this.text=a.text,this.newSel=vh(h,this.bounds.from)}else{let h=t.observer.selectionRange,a=n&&n.node==h.focusNode&&n.offset==h.focusOffset||!Os(t.contentDOM,h.focusNode)?l.main.head:t.docView.posFromDOM(h.focusNode,h.focusOffset),f=o&&o.node==h.anchorNode&&o.offset==h.anchorOffset||!Os(t.contentDOM,h.anchorNode)?l.main.anchor:t.docView.posFromDOM(h.anchorNode,h.anchorOffset),u=t.viewport;if((w.ios||w.chrome)&&a!=f&&Math.min(a,f)<=l.main.from&&Math.max(a,f)>=l.main.to&&(u.from>0||u.to-1&&l.ranges.length>1)this.newSel=l.replaceRange(k.range(f,a));else if(t.lineWrapping&&f==a&&!(l.main.empty&&l.main.head==a)&&t.inputState.lastTouchTime>Date.now()-100){let c=t.coordsAtPos(a,-1),d=0;c&&(d=t.inputState.lastTouchY<=c.bottom?-1:1),this.newSel=k.create([k.cursor(a,d)])}else this.newSel=k.single(f,a)}}}function uo(r,t,e,i){if(r.isComposite()){let s=-1,n=-1,o=-1,l=-1;for(let h=0,a=i,f=i;he)return uo(u,t,e,a);if(c>=t&&s==-1&&(s=h,n=a),a>e&&u.dom.parentNode==r.dom){o=h,l=f;break}f=c,a=c+u.breakAfter}return{from:n,to:l<0?i+r.length:l,startDOM:(s?r.children[s-1].dom.nextSibling:null)||r.dom.firstChild,endDOM:o=0?r.children[o].dom:null}}else return r.isText()?{from:i,to:i+r.length,startDOM:r.dom,endDOM:r.dom.nextSibling}:null}function co(r,t){let e,{newSel:i}=t,{state:s}=r,n=s.selection.main,o=r.inputState.lastKeyTime>Date.now()-100?r.inputState.lastKeyCode:-1;if(t.bounds){let{from:l,to:h}=t.bounds,a=n.from,f=null;(o===8||w.android&&t.text.length=l&&n.to<=h&&(t.typeOver||u!=t.text)&&u.slice(0,n.from-l)==t.text.slice(0,n.from-l)&&u.slice(n.to-l)==t.text.slice(c=t.text.length-(u.length-(n.to-l)))?e={from:n.from,to:n.to,insert:B.of(t.text.slice(n.from-l,c).split(re))}:(d=po(u,t.text,a-l,f))&&(w.chrome&&o==13&&d.toB==d.from+2&&t.text.slice(d.from,d.toB)==re+re&&d.toB--,e={from:l+d.from,to:l+d.toA,insert:B.of(t.text.slice(d.from,d.toB).split(re))})}else i&&(!r.hasFocus&&s.facet(Bt)||Bi(i,n))&&(i=null);if(!e&&!i)return!1;if((w.mac||w.android)&&e&&e.from==e.to&&e.from==n.head-1&&/^\. ?$/.test(e.insert.toString())&&r.contentDOM.getAttribute("autocorrect")=="off"?(i&&e.insert.length==2&&(i=k.single(i.main.anchor-1,i.main.head-1)),e={from:e.from,to:e.to,insert:B.of([e.insert.toString().replace("."," ")])}):s.doc.lineAt(n.from).toDate.now()-50?e={from:n.from,to:n.to,insert:s.toText(r.inputState.insertingText)}:w.chrome&&e&&e.from==e.to&&e.from==n.head&&e.insert.toString()==` + `&&r.lineWrapping&&(i&&(i=k.single(i.main.anchor-1,i.main.head-1)),e={from:n.from,to:n.to,insert:B.of([" "])}),e)return tn(r,e,i,o);if(i&&!Bi(i,n)){let l=!1,h="select";return r.inputState.lastSelectionTime>Date.now()-50&&(r.inputState.lastSelectionOrigin=="select"&&(l=!0),h=r.inputState.lastSelectionOrigin,h=="select.pointer"&&(i=fo(s.facet(Qe).map(a=>a(r)),i))),r.dispatch({selection:i,scrollIntoView:l,userEvent:h}),!0}else return!1}function tn(r,t,e,i=-1){if(w.ios&&r.inputState.flushIOSKey(t))return!0;let s=r.state.selection.main;if(w.android&&(t.to==s.to&&(t.from==s.from||t.from==s.from-1&&r.state.sliceDoc(t.from,s.from)==" ")&&t.insert.length==1&&t.insert.lines==2&&fe(r.contentDOM,"Enter",13)||(t.from==s.from-1&&t.to==s.to&&t.insert.length==0||i==8&&t.insert.lengths.head)&&fe(r.contentDOM,"Backspace",8)||t.from==s.from&&t.to==s.to+1&&t.insert.length==0&&fe(r.contentDOM,"Delete",46)))return!0;let n=t.insert.toString();r.inputState.composing>=0&&r.inputState.composing++;let o,l=()=>o||(o=kh(r,t,e));return r.state.facet(Jr).some(h=>h(r,t.from,t.to,n,l))||r.dispatch(l()),!0}function kh(r,t,e){let i,s=r.state,n=s.selection.main,o=-1;if(t.from==t.to&&t.fromn.to){let h=t.fromu(r)),a,h);t.from==f&&(o=f)}if(o>-1)i={changes:t,selection:k.cursor(t.from+t.insert.length,-1)};else if(t.from>=n.from&&t.to<=n.to&&t.to-t.from>=(n.to-n.from)/3&&(!e||e.main.empty&&e.main.from==t.from+t.insert.length)&&r.inputState.composing<0){let h=n.fromt.to?s.sliceDoc(t.to,n.to):"";i=s.replaceSelection(r.state.toText(h+t.insert.sliceString(0,void 0,r.state.lineBreak)+a))}else{let h=s.changes(t),a=e&&e.main.to<=h.newLength?e.main:void 0;if(s.selection.ranges.length>1&&(r.inputState.composing>=0||r.inputState.compositionPendingChange)&&t.to<=n.to+10&&t.to>=n.to-10){let f=r.state.sliceDoc(t.from,t.to),u,c=e&&ao(r,e.main.head);if(c){let p=t.insert.length-(t.to-t.from);u={from:c.from,to:c.to-p}}else u=r.state.doc.lineAt(n.head);let d=n.to-t.to;i=s.changeByRange(p=>{if(p.from==n.from&&p.to==n.to)return{changes:h,range:a||p.map(h)};let g=p.to-d,m=g-f.length;if(r.state.sliceDoc(m,g)!=f||g>=u.from&&m<=u.to)return{range:p};let b=s.changes({from:m,to:g,insert:t.insert}),y=p.to-n.to;return{changes:b,range:a?k.range(Math.max(0,a.anchor+y),Math.max(0,a.head+y)):p.map(b)}})}else i={changes:h,selection:a&&s.selection.replaceRange(a)}}let l="input.type";return(r.composing||r.inputState.compositionPendingChange&&r.inputState.compositionEndedAt>Date.now()-50)&&(r.inputState.compositionPendingChange=!1,l+=".compose",r.inputState.compositionFirstChange&&(l+=".start",r.inputState.compositionFirstChange=!1)),s.update(i,{userEvent:l,scrollIntoView:!0})}function po(r,t,e,i){let s=Math.min(r.length,t.length),n=0;for(;n0&&l>0&&r.charCodeAt(o-1)==t.charCodeAt(l-1);)o--,l--;if(i=="end"){let h=Math.max(0,n-Math.min(o,l));e-=o+h-n}if(o=o?n-e:0;n-=h,l=n+(l-o),o=n}else if(l=l?n-e:0;n-=h,o=n+(o-l),l=n}return{from:n,toA:o,toB:l}}function Sh(r){let t=[];if(r.root.activeElement!=r.contentDOM)return t;let{anchorNode:e,anchorOffset:i,focusNode:s,focusOffset:n}=r.observer.selectionRange;return e&&(t.push(new Vn(e,i)),(s!=e||n!=i)&&t.push(new Vn(s,n))),t}function vh(r,t){if(r.length==0)return null;let e=r[0].pos,i=r.length==2?r[1].pos:e;return e>-1&&i>-1?k.single(e+t,i+t):null}function Bi(r,t){return t.head==r.main.head&&t.anchor==r.main.anchor}class Ch{setSelectionOrigin(t){this.lastSelectionOrigin=t,this.lastSelectionTime=Date.now()}constructor(t){this.view=t,this.lastKeyCode=0,this.lastKeyTime=0,this.touchActive=!1,this.lastTouchTime=0,this.lastTouchX=0,this.lastTouchY=0,this.lastFocusTime=0,this.lastScrollTop=0,this.lastScrollLeft=0,this.lastWheelEvent=0,this.pendingIOSKey=void 0,this.lastIOSMomentumScroll=0,this.tabFocusMode=-1,this.lastSelectionOrigin=null,this.lastSelectionTime=0,this.lastContextMenu=0,this.scrollHandlers=[],this.handlers=Object.create(null),this.composing=-1,this.compositionFirstChange=null,this.compositionEndedAt=0,this.compositionPendingKey=!1,this.compositionPendingChange=!1,this.insertingText="",this.insertingTextAt=0,this.mouseSelection=null,this.draggedContent=null,this.handleEvent=this.handleEvent.bind(this),this.notifiedFocused=t.hasFocus,w.safari&&t.contentDOM.addEventListener("input",()=>null),w.gecko&&Vh(t.contentDOM.ownerDocument)}handleEvent(t){!Eh(this.view,t)||this.ignoreDuringComposition(t)||t.type=="keydown"&&this.keydown(t)||(this.view.updateState!=0?Promise.resolve().then(()=>this.runHandlers(t.type,t)):this.runHandlers(t.type,t))}runHandlers(t,e){let i=this.handlers[t];if(i){for(let s of i.observers)s(this.view,e);for(let s of i.handlers){if(e.defaultPrevented)break;if(s(this.view,e)){e.preventDefault();break}}}}ensureHandlers(t){let e=Oh(t),i=this.handlers,s=this.view.contentDOM;for(let n in e)if(n!="scroll"){let o=!e[n].handlers.length,l=i[n];l&&o!=!l.handlers.length&&(s.removeEventListener(n,this.handleEvent),l=null),l||s.addEventListener(n,this.handleEvent,{passive:o})}for(let n in i)n!="scroll"&&!e[n]&&s.removeEventListener(n,this.handleEvent);this.handlers=e}keydown(t){if(this.lastKeyCode=t.keyCode,this.lastKeyTime=Date.now(),t.keyCode==9&&this.tabFocusMode>-1&&(!this.tabFocusMode||Date.now()<=this.tabFocusMode))return!0;if(this.tabFocusMode>0&&t.keyCode!=27&&mo.indexOf(t.keyCode)<0&&(this.tabFocusMode=-1),w.android&&w.chrome&&!t.synthetic&&(t.keyCode==13||t.keyCode==8))return this.view.observer.delayAndroidKey(t.key,t.keyCode),!0;if(w.ios&&!t.synthetic&&!t.altKey&&!t.metaKey&&(go.some(e=>e.keyCode==t.keyCode)&&!t.ctrlKey||Th.indexOf(t.key)>-1&&t.ctrlKey)){let e={ctrlKey:t.ctrlKey,altKey:t.altKey,metaKey:t.metaKey,shiftKey:t.shiftKey};return e.shiftKey&&w.ios&&!/^(off|none)$/.test(this.view.contentDOM.autocapitalize)&&Ah(this.view.win)&&(e.shiftKey=!1),this.pendingIOSKey={key:t.key,keyCode:t.keyCode,mods:e},setTimeout(()=>this.flushIOSKey(),250),!0}return t.keyCode!=229&&this.view.observer.forceFlush(),!1}flushIOSKey(t){let e=this.pendingIOSKey;return!e||e.key=="Enter"&&t&&t.from0?!0:w.safari&&!w.ios&&this.compositionPendingKey&&Date.now()-this.compositionEndedAt<100?(this.compositionPendingKey=!1,!0):!1}startMouseSelection(t){this.mouseSelection&&this.mouseSelection.destroy(),this.mouseSelection=t}update(t){this.view.observer.update(t),this.mouseSelection&&this.mouseSelection.update(t),this.draggedContent&&t.docChanged&&(this.draggedContent=this.draggedContent.map(t.changes)),t.transactions.length&&(this.lastKeyCode=this.lastSelectionTime=0)}destroy(){this.mouseSelection&&this.mouseSelection.destroy()}}function Ah(r){return r.visualViewport?r.visualViewport.height*r.visualViewport.scale/r.document.documentElement.clientHeight<.85:!1}function zn(r,t){return(e,i)=>{try{return t.call(r,i,e)}catch(s){Tt(e.state,s)}}}function Oh(r){let t=Object.create(null);function e(i){return t[i]||(t[i]={observers:[],handlers:[]})}for(let i of r){let s=i.spec,n=s&&s.plugin.domEventHandlers,o=s&&s.plugin.domEventObservers;if(n)for(let l in n){let h=n[l];h&&e(l).handlers.push(zn(i.value,h))}if(o)for(let l in o){let h=o[l];h&&e(l).observers.push(zn(i.value,h))}}for(let i in bt)e(i).handlers.push(bt[i]);for(let i in nt)e(i).observers.push(nt[i]);return t}const go=[{key:"Backspace",keyCode:8,inputType:"deleteContentBackward"},{key:"Enter",keyCode:13,inputType:"insertParagraph"},{key:"Enter",keyCode:13,inputType:"insertLineBreak"},{key:"Delete",keyCode:46,inputType:"deleteContentForward"}],Th="dthko",mo=[16,17,18,20,91,92,224,225],ni=6;function ri(r){return Math.max(0,r)*.7+8}function Mh(r,t){return Math.max(Math.abs(r.clientX-t.clientX),Math.abs(r.clientY-t.clientY))}class Ph{constructor(t,e,i,s){this.view=t,this.startEvent=e,this.style=i,this.mustSelect=s,this.scrollSpeed={x:0,y:0},this.scrolling=-1,this.lastEvent=e,this.scrollParents=Fr(t.contentDOM),this.atoms=t.state.facet(Qe).map(o=>o(t));let n=t.contentDOM.ownerDocument;n.addEventListener("mousemove",this.move=this.move.bind(this)),n.addEventListener("mouseup",this.up=this.up.bind(this)),this.extend=e.shiftKey,this.multiple=t.state.facet(I.allowMultipleSelections)&&Dh(t,e),this.dragging=Rh(t,e)&&wo(e)==1?null:!1}start(t){this.dragging===!1&&this.select(t)}move(t){if(t.buttons==0)return this.destroy();if(this.dragging||this.dragging==null&&Mh(this.startEvent,t)<10)return;this.select(this.lastEvent=t);let e=0,i=0,s=0,n=0,o=this.view.win.innerWidth,l=this.view.win.innerHeight;this.scrollParents.x&&({left:s,right:o}=this.scrollParents.x.getBoundingClientRect()),this.scrollParents.y&&({top:n,bottom:l}=this.scrollParents.y.getBoundingClientRect());let h=lo(this.view);t.clientX-h.left<=s+ni?e=-ri(s-t.clientX):t.clientX+h.right>=o-ni&&(e=ri(t.clientX-o)),t.clientY-h.top<=n+ni?i=-ri(n-t.clientY):t.clientY+h.bottom>=l-ni&&(i=ri(t.clientY-l)),this.setScrollSpeed(e,i)}up(t){this.dragging==null&&this.select(this.lastEvent),this.dragging||t.preventDefault(),this.destroy()}destroy(){this.setScrollSpeed(0,0);let t=this.view.contentDOM.ownerDocument;t.removeEventListener("mousemove",this.move),t.removeEventListener("mouseup",this.up),this.view.inputState.mouseSelection=this.view.inputState.draggedContent=null}setScrollSpeed(t,e){this.scrollSpeed={x:t,y:e},t||e?this.scrolling<0&&(this.scrolling=setInterval(()=>this.scroll(),50)):this.scrolling>-1&&(clearInterval(this.scrolling),this.scrolling=-1)}scroll(){let{x:t,y:e}=this.scrollSpeed;t&&this.scrollParents.x&&(this.scrollParents.x.scrollLeft+=t,t=0),e&&this.scrollParents.y&&(this.scrollParents.y.scrollTop+=e,e=0),(t||e)&&this.view.win.scrollBy(t,e),this.dragging===!1&&this.select(this.lastEvent)}select(t){let{view:e}=this,i=fo(this.atoms,this.style.get(t,this.extend,this.multiple));(this.mustSelect||!i.eq(e.state.selection,this.dragging===!1))&&this.view.dispatch({selection:i,userEvent:"select.pointer"}),this.mustSelect=!1}update(t){t.transactions.some(e=>e.isUserEvent("input.type"))?this.destroy():this.style.update(t)&&setTimeout(()=>this.select(this.lastEvent),20)}}function Dh(r,t){let e=r.state.facet(Gr);return e.length?e[0](t):w.mac?t.metaKey:t.ctrlKey}function Bh(r,t){let e=r.state.facet(Yr);return e.length?e[0](t):w.mac?!t.altKey:!t.ctrlKey}function Rh(r,t){let{main:e}=r.state.selection;if(e.empty)return!1;let i=Ke(r.root);if(!i||i.rangeCount==0)return!0;let s=i.getRangeAt(0).getClientRects();for(let n=0;n=t.clientX&&o.top<=t.clientY&&o.bottom>=t.clientY)return!0}return!1}function Eh(r,t){if(!t.bubbles)return!0;if(t.defaultPrevented)return!1;for(let e=t.target,i;e!=r.contentDOM;e=e.parentNode)if(!e||e.nodeType==11||(i=q.get(e))&&i.isWidget()&&!i.isHidden&&i.widget.ignoreEvent(t))return!1;return!0}const bt=Object.create(null),nt=Object.create(null),bo=w.ie&&w.ie_version<15||w.ios&&w.webkit_version<604;function Nh(r){let t=r.dom.parentNode;if(!t)return;let e=t.appendChild(document.createElement("textarea"));e.style.cssText="position: fixed; left: -10000px; top: 10px",e.focus(),setTimeout(()=>{r.focus(),e.remove(),xo(r,e.value)},50)}function Ki(r,t,e){for(let i of r.facet(t))e=i(e,r);return e}function xo(r,t){t=Ki(r.state,Xs,t);let{state:e}=r,i,s=1,n=e.toText(t),o=n.lines==e.selection.ranges.length;if(Es!=null&&e.selection.ranges.every(h=>h.empty)&&Es==n.toString()){let h=-1;i=e.changeByRange(a=>{let f=e.doc.lineAt(a.from);if(f.from==h)return{range:a};h=f.from;let u=e.toText((o?n.line(s++).text:t)+e.lineBreak);return{changes:{from:f.from,insert:u},range:k.cursor(a.from+u.length)}})}else o?i=e.changeByRange(h=>{let a=n.line(s++);return{changes:{from:h.from,to:h.to,insert:a.text},range:k.cursor(h.from+a.length)}}):i=e.replaceSelection(n);r.dispatch(i,{userEvent:"input.paste",scrollIntoView:!0})}nt.scroll=r=>{let t=r.inputState;t.lastScrollTop=r.scrollDOM.scrollTop,t.lastScrollLeft=r.scrollDOM.scrollLeft,w.ios&&!t.touchActive&&(t.lastIOSMomentumScroll=Date.now())};nt.wheel=nt.mousewheel=r=>{r.inputState.lastWheelEvent=Date.now()};bt.keydown=(r,t)=>(r.inputState.setSelectionOrigin("select"),t.keyCode==27&&r.inputState.tabFocusMode!=0&&(r.inputState.tabFocusMode=Date.now()+2e3),!1);nt.touchstart=(r,t)=>{let e=r.inputState,i=t.targetTouches[0];e.touchActive=!0,e.lastTouchTime=Date.now(),i&&(e.lastTouchX=i.clientX,e.lastTouchY=i.clientY),e.setSelectionOrigin("select.pointer")};nt.touchmove=r=>{r.inputState.setSelectionOrigin("select.pointer")};nt.touchend=(r,t)=>{r.inputState.touchActive=!1};bt.mousedown=(r,t)=>{if(r.observer.flush(),r.inputState.lastTouchTime>Date.now()-2e3)return!1;let e=null;for(let i of r.state.facet(Xr))if(e=i(r,t),e)break;if(!e&&t.button==0&&(e=Lh(r,t)),e){let i=!r.hasFocus;r.inputState.startMouseSelection(new Ph(r,t,e,i)),i&&r.observer.ignore(()=>{Hr(r.contentDOM);let n=r.root.activeElement;n&&!n.contains(r.contentDOM)&&n.blur()});let s=r.inputState.mouseSelection;if(s)return s.start(t),s.dragging===!1}else r.inputState.setSelectionOrigin("select.pointer");return!1};function Kn(r,t,e,i){if(i==1)return k.cursor(t,e);if(i==2)return fh(r.state,t,e);{let s=r.docView.lineAt(t,e),n=r.state.doc.lineAt(s?s.posAtEnd:t),o=s?s.posAtStart:n.from,l=s?s.posAtEnd:n.to;return lDate.now()-400&&Math.abs(t.clientX-r.clientX)<2&&Math.abs(t.clientY-r.clientY)<2?(qn+1)%3:1}function Lh(r,t){let e=r.posAndSideAtCoords({x:t.clientX,y:t.clientY},!1),i=wo(t),s=r.state.selection;return{update(n){n.docChanged&&(e.pos=n.changes.mapPos(e.pos),s=s.map(n.changes))},get(n,o,l){let h=r.posAndSideAtCoords({x:n.clientX,y:n.clientY},!1),a,f=Kn(r,h.pos,h.assoc,i);if(e.pos!=h.pos&&!o){let u=Kn(r,e.pos,e.assoc,i),c=Math.min(u.from,f.from),d=Math.max(u.to,f.to);f=c1&&(a=Wh(s,h.pos))?a:l?s.addRange(f):k.create([f])}}}function Wh(r,t){for(let e=0;e=t)return k.create(r.ranges.slice(0,e).concat(r.ranges.slice(e+1)),r.mainIndex==e?0:r.mainIndex-(r.mainIndex>e?1:0))}return null}bt.dragstart=(r,t)=>{let{selection:{main:e}}=r.state;if(t.target.draggable){let s=r.docView.tile.nearest(t.target);if(s&&s.isWidget()){let n=s.posAtStart,o=n+s.length;(n>=e.to||o<=e.from)&&(e=k.undirectionalRange(n,o))}}let{inputState:i}=r;return i.mouseSelection&&(i.mouseSelection.dragging=!0),i.draggedContent=e,t.dataTransfer&&(t.dataTransfer.setData("Text",Ki(r.state,_s,r.state.sliceDoc(e.from,e.to))),t.dataTransfer.effectAllowed="copyMove"),!1};bt.dragend=r=>(r.inputState.draggedContent=null,!1);function Qn(r,t,e,i){if(e=Ki(r.state,Xs,e),!e)return;let s=r.posAtCoords({x:t.clientX,y:t.clientY},!1),{draggedContent:n}=r.inputState,o=i&&n&&Bh(r,t)?{from:n.from,to:n.to}:null,l={from:s,insert:e},h=r.state.changes(o?[o,l]:l);r.focus(),r.dispatch({changes:h,selection:{anchor:h.mapPos(s,-1),head:h.mapPos(s,1)},userEvent:o?"move.drop":"input.drop"}),r.inputState.draggedContent=null}bt.drop=(r,t)=>{if(!t.dataTransfer)return!1;if(r.state.readOnly)return!0;let e=t.dataTransfer.files;if(e&&e.length){let i=Array(e.length),s=0,n=()=>{++s==e.length&&Qn(r,t,i.filter(o=>o!=null).join(r.state.lineBreak),!1)};for(let o=0;o{/[\x00-\x08\x0e-\x1f]{2}/.test(l.result)||(i[o]=l.result),n()},l.readAsText(e[o])}return!0}else{let i=t.dataTransfer.getData("Text");if(i)return Qn(r,t,i,!0),!0}return!1};bt.paste=(r,t)=>{if(r.state.readOnly)return!0;r.observer.flush();let e=bo?null:t.clipboardData;return e?(xo(r,e.getData("text/plain")||e.getData("text/uri-list")),!0):(Nh(r),!1)};function Fh(r,t){let e=r.dom.parentNode;if(!e)return;let i=e.appendChild(document.createElement("textarea"));i.style.cssText="position: fixed; left: -10000px; top: 10px",i.value=t,i.focus(),i.selectionEnd=t.length,i.selectionStart=0,setTimeout(()=>{i.remove(),r.focus()},50)}function Hh(r){let t=[],e=[],i=!1;for(let s of r.selection.ranges)s.empty||(t.push(r.sliceDoc(s.from,s.to)),e.push(s));if(!t.length){let s=-1;for(let{from:n}of r.selection.ranges){let o=r.doc.lineAt(n);o.number>s&&(t.push(o.text),e.push({from:o.from,to:Math.min(r.doc.length,o.to+1)})),s=o.number}i=!0}return{text:Ki(r,_s,t.join(r.lineBreak)),ranges:e,linewise:i}}let Es=null;bt.copy=bt.cut=(r,t)=>{if(!Ee(r.contentDOM,r.observer.selectionRange))return!1;let{text:e,ranges:i,linewise:s}=Hh(r.state);if(!e&&!s)return!1;Es=s?e:null,t.type=="cut"&&!r.state.readOnly&&r.dispatch({changes:i,scrollIntoView:!0,userEvent:"delete.cut"});let n=bo?null:t.clipboardData;return n?(n.clearData(),n.setData("text/plain",e),!0):(Fh(r,e),!1)};const yo=ke.define();function ko(r,t){let e=[];for(let i of r.facet(Zr)){let s=i(r,t);s&&e.push(s)}return e.length?r.update({effects:e,annotations:yo.of(!0)}):null}function So(r){setTimeout(()=>{let t=r.hasFocus;if(t!=r.inputState.notifiedFocused){let e=ko(r.state,t);e?r.dispatch(e):r.update([])}},10)}nt.focus=r=>{r.inputState.lastFocusTime=Date.now(),!r.scrollDOM.scrollTop&&(r.inputState.lastScrollTop||r.inputState.lastScrollLeft)&&(r.scrollDOM.scrollTop=r.inputState.lastScrollTop,r.scrollDOM.scrollLeft=r.inputState.lastScrollLeft),So(r)};nt.blur=r=>{r.observer.clearSelectionRange(),So(r)};nt.compositionstart=nt.compositionupdate=r=>{r.observer.editContext||(r.inputState.compositionFirstChange==null&&(r.inputState.compositionFirstChange=!0),r.inputState.composing<0&&(r.inputState.composing=0))};nt.compositionend=r=>{r.observer.editContext||(r.inputState.composing=-1,r.inputState.compositionEndedAt=Date.now(),r.inputState.compositionPendingKey=!0,r.inputState.compositionPendingChange=r.observer.pendingRecords().length>0,r.inputState.compositionFirstChange=null,w.chrome&&w.android?r.observer.flushSoon():r.inputState.compositionPendingChange?Promise.resolve().then(()=>r.observer.flush()):setTimeout(()=>{r.inputState.composing<0&&r.docView.hasComposition&&r.update([])},50))};nt.contextmenu=r=>{r.inputState.lastContextMenu=Date.now()};bt.beforeinput=(r,t)=>{var e,i;if((t.inputType=="insertText"||t.inputType=="insertCompositionText")&&(r.inputState.insertingText=t.data,r.inputState.insertingTextAt=Date.now()),t.inputType=="insertReplacementText"&&r.observer.editContext){let n=(e=t.dataTransfer)===null||e===void 0?void 0:e.getData("text/plain"),o=t.getTargetRanges();if(n&&o.length){let l=o[0],h=r.posAtDOM(l.startContainer,l.startOffset),a=r.posAtDOM(l.endContainer,l.endOffset);return tn(r,{from:h,to:a,insert:r.state.toText(n)},null),!0}}let s;if(w.chrome&&w.android&&(s=go.find(n=>n.inputType==t.inputType))&&(r.observer.delayAndroidKey(s.key,s.keyCode),s.key=="Backspace"||s.key=="Delete")){let n=((i=window.visualViewport)===null||i===void 0?void 0:i.height)||0;setTimeout(()=>{var o;(((o=window.visualViewport)===null||o===void 0?void 0:o.height)||0)>n+10&&r.hasFocus&&(r.contentDOM.blur(),r.focus())},100)}return w.ios&&t.inputType=="deleteContentForward"&&r.observer.flushSoon(),w.safari&&t.inputType=="insertText"&&r.inputState.composing>=0&&setTimeout(()=>nt.compositionend(r,t),20),!1};const Un=new Set;function Vh(r){Un.has(r)||(Un.add(r),r.addEventListener("copy",()=>{}),r.addEventListener("cut",()=>{}))}const Gn=["pre-wrap","normal","pre-line","break-spaces"];let be=!1;function Yn(){be=!1}class zh{constructor(t){this.lineWrapping=t,this.doc=B.empty,this.heightSamples={},this.lineHeight=14,this.charWidth=7,this.textHeight=14,this.lineLength=30}heightForGap(t,e){let i=this.doc.lineAt(e).number-this.doc.lineAt(t).number+1;return this.lineWrapping&&(i+=Math.max(0,Math.ceil((e-t-i*this.lineLength*.5)/this.lineLength))),this.lineHeight*i}heightForLine(t){return this.lineWrapping?(1+Math.max(0,Math.ceil((t-this.lineLength)/Math.max(1,this.lineLength-5))))*this.lineHeight:this.lineHeight}setDoc(t){return this.doc=t,this}mustRefreshForWrapping(t){return Gn.indexOf(t)>-1!=this.lineWrapping}mustRefreshForHeights(t){let e=!1;for(let i=0;i-1,h=Math.abs(e-this.lineHeight)>.3||this.lineWrapping!=l;if(this.lineWrapping=l,this.lineHeight=e,this.charWidth=i,this.textHeight=s,this.lineLength=n,h){this.heightSamples={};for(let a=0;a0}set outdated(t){this.flags=(t?2:0)|this.flags&-3}setHeight(t){this.height!=t&&(Math.abs(this.height-t)>mi&&(be=!0),this.height=t)}replace(t,e,i){return st.of(i)}decomposeLeft(t,e){e.push(this)}decomposeRight(t,e){e.push(this)}applyChanges(t,e,i,s){let n=this,o=i.doc;for(let l=s.length-1;l>=0;l--){let{fromA:h,toA:a,fromB:f,toB:u}=s[l],c=n.lineAt(h,F.ByPosNoHeight,i.setDoc(e),0,0),d=c.to>=a?c:n.lineAt(a,F.ByPosNoHeight,i,0,0);for(u+=d.to-a,a=d.to;l>0&&c.from<=s[l-1].toA;)h=s[l-1].fromA,f=s[l-1].fromB,l--,hn*2){let l=t[e-1];l.break?t.splice(--e,1,l.left,null,l.right):t.splice(--e,1,l.left,l.right),i+=1+l.break,s-=l.size}else if(n>s*2){let l=t[i];l.break?t.splice(i,1,l.left,null,l.right):t.splice(i,1,l.left,l.right),i+=2+l.break,n-=l.size}else break;else if(s=n&&o(this.lineAt(0,F.ByPos,i,s,n))}setMeasuredHeight(t){let e=t.heights[t.index++];e<0?(this.spaceAbove=-e,e=t.heights[t.index++]):this.spaceAbove=0,this.setHeight(e)}updateHeight(t,e=0,i=!1,s){return s&&s.from<=e&&s.more&&this.setMeasuredHeight(s),this.outdated=!1,this}toString(){return`block(${this.length})`}}class ht extends vo{constructor(t,e,i){super(t,e,null),this.collapsed=0,this.widgetHeight=0,this.breaks=0,this.spaceAbove=i}mainBlock(t,e){return new gt(e,this.length,t+this.spaceAbove,this.height-this.spaceAbove,this.breaks)}replace(t,e,i){let s=i[0];return i.length==1&&(s instanceof ht||s instanceof _&&s.flags&4)&&Math.abs(this.length-s.length)<10?(s instanceof _?s=new ht(s.length,this.height,this.spaceAbove):s.height=this.height,this.outdated||(s.outdated=!1),s):st.of(i)}updateHeight(t,e=0,i=!1,s){return s&&s.from<=e&&s.more?this.setMeasuredHeight(s):(i||this.outdated)&&(this.spaceAbove=0,this.setHeight(Math.max(this.widgetHeight,t.heightForLine(this.length-this.collapsed))+this.breaks*t.lineHeight)),this.outdated=!1,this}toString(){return`line(${this.length}${this.collapsed?-this.collapsed:""}${this.widgetHeight?":"+this.widgetHeight:""})`}}class _ extends st{constructor(t){super(t,0)}heightMetrics(t,e){let i=t.doc.lineAt(e).number,s=t.doc.lineAt(e+this.length).number,n=s-i+1,o,l=0;if(t.lineWrapping){let h=Math.min(this.height,t.lineHeight*n);o=h/n,this.length>n+1&&(l=(this.height-h)/(this.length-n-1))}else o=this.height/n;return{firstLine:i,lastLine:s,perLine:o,perChar:l}}blockAt(t,e,i,s){let{firstLine:n,lastLine:o,perLine:l,perChar:h}=this.heightMetrics(e,s);if(e.lineWrapping){let a=s+(t0){let n=i[i.length-1];n instanceof _?i[i.length-1]=new _(n.length+s):i.push(null,new _(s-1))}if(t>0){let n=i[0];n instanceof _?i[0]=new _(t+n.length):i.unshift(new _(t-1),null)}return st.of(i)}decomposeLeft(t,e){e.push(new _(t-1),null)}decomposeRight(t,e){e.push(null,new _(this.length-t-1))}updateHeight(t,e=0,i=!1,s){let n=e+this.length;if(s&&s.from<=e+this.length&&s.more){let o=[],l=Math.max(e,s.from),h=-1;for(s.from>e&&o.push(new _(s.from-e-1).updateHeight(t,e));l<=n&&s.more;){let f=t.doc.lineAt(l).length;o.length&&o.push(null);let u=s.heights[s.index++],c=0;u<0&&(c=-u,u=s.heights[s.index++]),h==-1?h=u:Math.abs(u-h)>=mi&&(h=-2);let d=new ht(f,u,c);d.outdated=!1,o.push(d),l+=f+1}l<=n&&o.push(null,new _(n-l).updateHeight(t,l));let a=st.of(o);return(h<0||Math.abs(a.height-this.height)>=mi||Math.abs(h-this.heightMetrics(t,e).perLine)>=mi)&&(be=!0),Ri(this,a)}else(i||this.outdated)&&(this.setHeight(t.heightForGap(e,e+this.length)),this.outdated=!1);return this}toString(){return`gap(${this.length})`}}class qh extends st{constructor(t,e,i){super(t.length+e+i.length,t.height+i.height,e|(t.outdated||i.outdated?2:0)),this.left=t,this.right=i,this.size=t.size+i.size}get break(){return this.flags&1}blockAt(t,e,i,s){let n=i+this.left.height;return tl))return a;let f=e==F.ByPosNoHeight?F.ByPosNoHeight:F.ByPos;return h?a.join(this.right.lineAt(l,f,i,o,l)):this.left.lineAt(l,f,i,s,n).join(a)}forEachLine(t,e,i,s,n,o){let l=s+this.left.height,h=n+this.left.length+this.break;if(this.break)t=h&&this.right.forEachLine(t,e,i,l,h,o);else{let a=this.lineAt(h,F.ByPos,i,s,n);t=t&&a.from<=e&&o(a),e>a.to&&this.right.forEachLine(a.to+1,e,i,l,h,o)}}replace(t,e,i){let s=this.left.length+this.break;if(ethis.left.length)return this.balanced(this.left,this.right.replace(t-s,e-s,i));let n=[];t>0&&this.decomposeLeft(t,n);let o=n.length;for(let l of i)n.push(l);if(t>0&&Xn(n,o-1),e=i&&e.push(null)),t>i&&this.right.decomposeLeft(t-i,e)}decomposeRight(t,e){let i=this.left.length,s=i+this.break;if(t>=s)return this.right.decomposeRight(t-s,e);t2*e.size||e.size>2*t.size?st.of(this.break?[t,null,e]:[t,e]):(this.left=Ri(this.left,t),this.right=Ri(this.right,e),this.setHeight(t.height+e.height),this.outdated=t.outdated||e.outdated,this.size=t.size+e.size,this.length=t.length+this.break+e.length,this)}updateHeight(t,e=0,i=!1,s){let{left:n,right:o}=this,l=e+n.length+this.break,h=null;return s&&s.from<=e+n.length&&s.more?h=n=n.updateHeight(t,e,i,s):n.updateHeight(t,e,i),s&&s.from<=l+o.length&&s.more?h=o=o.updateHeight(t,l,i,s):o.updateHeight(t,l,i),h?this.balanced(n,o):(this.height=this.left.height+this.right.height,this.outdated=!1,this)}toString(){return this.left+(this.break?" ":"-")+this.right}}function Xn(r,t){let e,i;r[t]==null&&(e=r[t-1])instanceof _&&(i=r[t+1])instanceof _&&r.splice(t-1,3,new _(e.length+1+i.length))}const jh=5;class en{constructor(t,e){this.pos=t,this.oracle=e,this.nodes=[],this.lineStart=-1,this.lineEnd=-1,this.covering=null,this.writtenTo=t}get isCovered(){return this.covering&&this.nodes[this.nodes.length-1]==this.covering}span(t,e){if(this.lineStart>-1){let i=Math.min(e,this.lineEnd),s=this.nodes[this.nodes.length-1];s instanceof ht?s.length+=i-this.pos:(i>this.pos||!this.isCovered)&&this.nodes.push(new ht(i-this.pos,-1,0)),this.writtenTo=i,e>i&&(this.nodes.push(null),this.writtenTo++,this.lineStart=-1)}this.pos=e}point(t,e,i){if(t=jh)&&this.addLineDeco(s,n,o)}else e>t&&this.span(t,e);this.lineEnd>-1&&this.lineEnd-1)return;let{from:t,to:e}=this.oracle.doc.lineAt(this.pos);this.lineStart=t,this.lineEnd=e,this.writtenTot&&this.nodes.push(new ht(this.pos-t,-1,0)),this.writtenTo=this.pos}blankContent(t,e){let i=new _(e-t);return this.oracle.doc.lineAt(t).to==e&&(i.flags|=4),i}ensureLine(){this.enterLine();let t=this.nodes.length?this.nodes[this.nodes.length-1]:null;if(t instanceof ht)return t;let e=new ht(0,-1,0);return this.nodes.push(e),e}addBlock(t){this.enterLine();let e=t.deco;e&&e.startSide>0&&!this.isCovered&&this.ensureLine(),this.nodes.push(t),this.writtenTo=this.pos=this.pos+t.length,e&&e.endSide>0&&(this.covering=t)}addLineDeco(t,e,i){let s=this.ensureLine();s.length+=i,s.collapsed+=i,s.widgetHeight=Math.max(s.widgetHeight,t),s.breaks+=e,this.writtenTo=this.pos=this.pos+i}finish(t){let e=this.nodes.length==0?null:this.nodes[this.nodes.length-1];this.lineStart>-1&&!(e instanceof ht)&&!this.isCovered?this.nodes.push(new ht(0,-1,0)):(this.writtenTof.clientHeight||f.scrollWidth>f.clientWidth)&&u.overflow!="visible"){let c=f.getBoundingClientRect();n=Math.max(n,c.left),o=Math.min(o,c.right),l=Math.max(l,c.top),h=Math.min(a==r.parentNode?s.innerHeight:h,c.bottom)}a=u.position=="absolute"||u.position=="fixed"?f.offsetParent:f.parentNode}else if(a.nodeType==11)a=a.host;else break;return{left:n-e.left,right:Math.max(n,o)-e.left,top:l-(e.top+t),bottom:Math.max(l,h)-(e.top+t)}}function Yh(r){let t=r.getBoundingClientRect(),e=r.ownerDocument.defaultView||window;return t.left0&&t.top0}function Xh(r,t){let e=r.getBoundingClientRect();return{left:0,right:e.right-e.left,top:t,bottom:e.bottom-(e.top+t)}}class es{constructor(t,e,i,s){this.from=t,this.to=e,this.size=i,this.displaySize=s}static same(t,e){if(t.length!=e.length)return!1;for(let i=0;itypeof s!="function"&&s.class=="cm-lineWrapping");this.heightOracle=new zh(i),this.stateDeco=Zn(e),this.heightMap=st.empty().applyChanges(this.stateDeco,B.empty,this.heightOracle.setDoc(e.doc),[new ct(0,0,0,e.doc.length)]);for(let s=0;s<2&&(this.viewport=this.getViewport(0,null),!!this.updateForViewport());s++);this.updateViewportLines(),this.lineGaps=this.ensureLineGaps([]),this.lineGapDeco=et.set(this.lineGaps.map(s=>s.draw(this,!1))),this.scrollParent=t.scrollDOM,this.computeVisibleRanges()}updateForViewport(){let t=[this.viewport],{main:e}=this.state.selection;for(let i=0;i<=1;i++){let s=i?e.head:e.anchor;if(!t.some(({from:n,to:o})=>s>=n&&s<=o)){let{from:n,to:o}=this.lineBlockAt(s);t.push(new oi(n,o))}}return this.viewports=t.sort((i,s)=>i.from-s.from),this.updateScaler()}updateScaler(){let t=this.scaler;return this.scaler=this.heightMap.height<=7e6?Jn:new sn(this.heightOracle,this.heightMap,this.viewports),t.eq(this.scaler)?0:2}updateViewportLines(){this.viewportLines=[],this.heightMap.forEachLine(this.viewport.from,this.viewport.to,this.heightOracle.setDoc(this.state.doc),0,0,t=>{this.viewportLines.push(Me(t,this.scaler))})}update(t,e=null){this.state=t.state;let i=this.stateDeco;this.stateDeco=Zn(this.state);let s=t.changedRanges,n=ct.extendWithRanges(s,Qh(i,this.stateDeco,t?t.changes:Y.empty(this.state.doc.length))),o=this.heightMap.height,l=this.scrolledToBottom?null:this.scrollAnchorAt(this.scrollOffset);Yn(),this.heightMap=this.heightMap.applyChanges(this.stateDeco,t.startState.doc,this.heightOracle.setDoc(this.state.doc),n),(this.heightMap.height!=o||be)&&(t.flags|=2),l?(this.scrollAnchorPos=t.changes.mapPos(l.from,-1),this.scrollAnchorHeight=l.top):(this.scrollAnchorPos=-1,this.scrollAnchorHeight=o);let h=n.length?this.mapViewport(this.viewport,t.changes):this.viewport;(e&&(e.range.headh.to)||!this.viewportIsAppropriate(h))&&(h=this.getViewport(0,e));let a=h.from!=this.viewport.from||h.to!=this.viewport.to;this.viewport=h,t.flags|=this.updateForViewport(),(a||!t.changes.empty||t.flags&2)&&this.updateViewportLines(),(this.lineGaps.length||this.viewport.to-this.viewport.from>4e3)&&this.updateLineGaps(this.ensureLineGaps(this.mapLineGaps(this.lineGaps,t.changes))),t.flags|=this.computeVisibleRanges(t.changes),e&&(this.scrollTarget=e),!this.mustEnforceCursorAssoc&&(t.selectionSet||t.focusChanged)&&t.view.lineWrapping&&t.state.selection.main.empty&&t.state.selection.main.assoc&&!t.state.facet(zl)&&(this.mustEnforceCursorAssoc=!0)}measure(){let{view:t}=this,e=t.contentDOM,i=window.getComputedStyle(e),s=this.heightOracle,n=i.whiteSpace;this.defaultTextDirection=i.direction=="rtl"?G.RTL:G.LTR;let o=this.heightOracle.mustRefreshForWrapping(n)||this.mustMeasureContent==="refresh",l=e.getBoundingClientRect(),h=o||this.mustMeasureContent||this.contentDOMHeight!=l.height;this.contentDOMHeight=l.height,this.mustMeasureContent=!1;let a=0,f=0;if(l.width&&l.height){let{scaleX:T,scaleY:C}=Wr(e,l);(T>.005&&Math.abs(this.scaleX-T)>.005||C>.005&&Math.abs(this.scaleY-C)>.005)&&(this.scaleX=T,this.scaleY=C,a|=16,o=h=!0)}let u=(parseInt(i.paddingTop)||0)*this.scaleY,c=(parseInt(i.paddingBottom)||0)*this.scaleY;(this.paddingTop!=u||this.paddingBottom!=c)&&(this.paddingTop=u,this.paddingBottom=c,a|=18),this.editorWidth!=t.scrollDOM.clientWidth&&(s.lineWrapping&&(h=!0),this.editorWidth=t.scrollDOM.clientWidth,a|=16);let d=Fr(this.view.contentDOM,!1).y;d!=this.scrollParent&&(this.scrollParent=d,this.scrollAnchorHeight=-1,this.scrollOffset=0);let p=this.getScrollOffset();this.scrollOffset!=p&&(this.scrollAnchorHeight=-1,this.scrollOffset=p),this.scrolledToBottom=Vr(this.scrollParent||t.win);let g=(this.printing?Xh:Gh)(e,this.paddingTop),m=g.top-this.pixelViewport.top,b=g.bottom-this.pixelViewport.bottom;this.pixelViewport=g;let y=this.pixelViewport.bottom>this.pixelViewport.top&&this.pixelViewport.right>this.pixelViewport.left;if(y!=this.inView&&(this.inView=y,y&&(h=!0)),!this.inView&&!this.scrollTarget&&!Yh(t.dom))return 0;let v=l.width;if((this.contentDOMWidth!=v||this.editorHeight!=t.scrollDOM.clientHeight)&&(this.contentDOMWidth=l.width,this.editorHeight=t.scrollDOM.clientHeight,a|=16),h){let T=t.docView.measureVisibleLineHeights(this.viewport);if(s.mustRefreshForHeights(T)&&(o=!0),o||s.lineWrapping&&Math.abs(v-this.contentDOMWidth)>s.charWidth){let{lineHeight:C,charWidth:S,textHeight:H}=t.docView.measureTextSize();o=C>0&&s.refresh(n,C,S,H,Math.max(5,v/S),T),o&&(t.docView.minWidth=0,a|=16)}m>0&&b>0?f=Math.max(m,b):m<0&&b<0&&(f=Math.min(m,b)),Yn();for(let C of this.viewports){let S=C.from==this.viewport.from?T:t.docView.measureVisibleLineHeights(C);this.heightMap=(o?st.empty().applyChanges(this.stateDeco,B.empty,this.heightOracle,[new ct(0,0,0,t.state.doc.length)]):this.heightMap).updateHeight(s,0,o,new Kh(C.from,S))}be&&(a|=2)}let E=!this.viewportIsAppropriate(this.viewport,f)||this.scrollTarget&&(this.scrollTarget.range.headthis.viewport.to);return E&&(a&2&&(a|=this.updateScaler()),this.viewport=this.getViewport(f,this.scrollTarget),a|=this.updateForViewport()),(a&2||E)&&this.updateViewportLines(),(this.lineGaps.length||this.viewport.to-this.viewport.from>4e3)&&this.updateLineGaps(this.ensureLineGaps(o?[]:this.lineGaps,t)),a|=this.computeVisibleRanges(),this.mustEnforceCursorAssoc&&(this.mustEnforceCursorAssoc=!1,t.docView.enforceCursorAssoc()),a}get visibleTop(){return this.scaler.fromDOM(this.pixelViewport.top)}get visibleBottom(){return this.scaler.fromDOM(this.pixelViewport.bottom)}getViewport(t,e){let i=.5-Math.max(-.5,Math.min(.5,t/1e3/2)),s=this.heightMap,n=this.heightOracle,{visibleTop:o,visibleBottom:l}=this,h=new oi(s.lineAt(o-i*1e3,F.ByHeight,n,0,0).from,s.lineAt(l+(1-i)*1e3,F.ByHeight,n,0,0).to);if(e){let{head:a}=e.range;if(ah.to){let f=Math.min(this.editorHeight,this.pixelViewport.bottom-this.pixelViewport.top),u=s.lineAt(a,F.ByPos,n,0,0),c;e.y=="center"?c=(u.top+u.bottom)/2-f/2:e.y=="start"||e.y=="nearest"&&a=l+Math.max(10,Math.min(i,250)))&&s>o-2*1e3&&n>1,o=s<<1;if(this.defaultTextDirection!=G.LTR&&!i)return[];let l=[],h=(f,u,c,d)=>{if(u-ff&&bb.from>=c.from&&b.to<=c.to&&Math.abs(b.from-f)b.fromy));if(!m){if(uv.from<=u&&v.to>=u)){let v=e.moveToLineBoundary(k.cursor(u),!1,!0).head;v>f&&(u=v)}let b=this.gapSize(c,f,u,d),y=i||b<2e6?b:2e6;m=new es(f,u,b,y)}l.push(m)},a=f=>{if(f.length2e6)for(let C of t)C.from>=f.from&&C.fromf.from&&h(f.from,d,f,u),pe.draw(this,this.heightOracle.lineWrapping))))}computeVisibleRanges(t){let e=this.stateDeco;this.lineGaps.length&&(e=e.concat(this.lineGapDeco));let i=[];N.spans(e,this.viewport.from,this.viewport.to,{span(n,o){i.push({from:n,to:o})},point(){}},20);let s=0;if(i.length!=this.visibleRanges.length)s=12;else for(let n=0;n=this.viewport.from&&t<=this.viewport.to&&this.viewportLines.find(e=>e.from<=t&&e.to>=t)||Me(this.heightMap.lineAt(t,F.ByPos,this.heightOracle,0,0),this.scaler)}lineBlockAtHeight(t){return t>=this.viewportLines[0].top&&t<=this.viewportLines[this.viewportLines.length-1].bottom&&this.viewportLines.find(e=>e.top<=t&&e.bottom>=t)||Me(this.heightMap.lineAt(this.scaler.fromDOM(t),F.ByHeight,this.heightOracle,0,0),this.scaler)}getScrollOffset(){return(this.scrollParent==this.view.scrollDOM?this.scrollParent.scrollTop:(this.scrollParent?this.scrollParent.getBoundingClientRect().top:0)-this.view.contentDOM.getBoundingClientRect().top)*this.scaleY}scrollAnchorAt(t){let e=this.lineBlockAtHeight(t+8);return e.from>=this.viewport.from||this.viewportLines[0].top-t>200?e:this.viewportLines[0]}elementAtHeight(t){return Me(this.heightMap.blockAt(this.scaler.fromDOM(t),this.heightOracle,0,0),this.scaler)}get docHeight(){return this.scaler.toDOM(this.heightMap.height)}get contentHeight(){return this.docHeight+this.paddingTop+this.paddingBottom}}class oi{constructor(t,e){this.from=t,this.to=e}}function Jh(r,t,e){let i=[],s=r,n=0;return N.spans(e,r,t,{span(){},point(o,l){o>s&&(i.push({from:s,to:o}),n+=o-s),s=l}},20),s=1)return t[t.length-1].to;let i=Math.floor(r*e);for(let s=0;;s++){let{from:n,to:o}=t[s],l=o-n;if(i<=l)return n+i;i-=l}}function hi(r,t){let e=0;for(let{from:i,to:s}of r.ranges){if(t<=s){e+=t-i;break}e+=s-i}return e/r.total}function Zh(r,t){for(let e of r)if(t(e))return e}const Jn={toDOM(r){return r},fromDOM(r){return r},scale:1,eq(r){return r==this}};function Zn(r){let t=r.facet(Hi).filter(i=>typeof i!="function"),e=r.facet(Zs).filter(i=>typeof i!="function");return e.length&&t.push(N.join(e)),t}class sn{constructor(t,e,i){let s=0,n=0,o=0;this.viewports=i.map(({from:l,to:h})=>{let a=e.lineAt(l,F.ByPos,t,0,0).top,f=e.lineAt(h,F.ByPos,t,0,0).bottom;return s+=f-a,{from:l,to:h,top:a,bottom:f,domTop:0,domBottom:0}}),this.scale=(7e6-s)/(e.height-s);for(let l of this.viewports)l.domTop=o+(l.top-n)*this.scale,o=l.domBottom=l.domTop+(l.bottom-l.top),n=l.bottom}toDOM(t){for(let e=0,i=0,s=0;;e++){let n=ee.from==t.viewports[i].from&&e.to==t.viewports[i].to):!1}}function Me(r,t){if(t.scale==1)return r;let e=t.toDOM(r.top),i=t.toDOM(r.bottom);return new gt(r.from,r.length,e,i-e,Array.isArray(r._content)?r._content.map(s=>Me(s,t)):r._content)}const ai=M.define({combine:r=>r.join(" ")}),Ns=M.define({combine:r=>r.indexOf(!0)>-1}),Is=de.newName(),Co=de.newName(),Ao=de.newName(),Oo={"&light":"."+Co,"&dark":"."+Ao};function Ls(r,t,e){return new de(t,{finish(i){return/&/.test(i)?i.replace(/&\w*/,s=>{if(s=="&")return r;if(!e||!e[s])throw new RangeError(`Unsupported selector: ${s}`);return e[s]}):r+" "+i}})}const ta=Ls("."+Is,{"&":{position:"relative !important",boxSizing:"border-box","&.cm-focused":{outline:"1px dotted #212121"},display:"flex !important",flexDirection:"column"},".cm-scroller":{display:"flex !important",alignItems:"flex-start !important",fontFamily:"monospace",lineHeight:1.4,height:"100%",overflowX:"auto",position:"relative",zIndex:0,overflowAnchor:"none"},".cm-content":{margin:0,flexGrow:2,flexShrink:0,display:"block",whiteSpace:"pre",wordWrap:"normal",boxSizing:"border-box",minHeight:"100%",padding:"4px 0",outline:"none","&[contenteditable=true]":{WebkitUserModify:"read-write-plaintext-only"}},".cm-lineWrapping":{whiteSpace_fallback:"pre-wrap",whiteSpace:"break-spaces",wordBreak:"break-word",overflowWrap:"anywhere",flexShrink:1},"&light .cm-content":{caretColor:"black"},"&dark .cm-content":{caretColor:"white"},".cm-line":{display:"block",padding:"0 2px 0 6px"},".cm-layer":{userSelect:"none",position:"absolute",left:0,top:0,contain:"size style","& > *":{position:"absolute"}},"&light .cm-selectionBackground":{background:"#d9d9d9"},"&dark .cm-selectionBackground":{background:"#222"},"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground":{background:"#d7d4f0"},"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground":{background:"#233"},".cm-cursorLayer":{pointerEvents:"none"},"&.cm-focused > .cm-scroller > .cm-cursorLayer":{animation:"steps(1) cm-blink 1.2s infinite"},"@keyframes cm-blink":{"0%":{},"50%":{opacity:0},"100%":{}},"@keyframes cm-blink2":{"0%":{},"50%":{opacity:0},"100%":{}},".cm-cursor, .cm-dropCursor":{borderLeft:"1.2px solid black",marginLeft:"-0.6px",pointerEvents:"none"},".cm-cursor":{display:"none"},"&dark .cm-cursor":{borderLeftColor:"#ddd"},".cm-selectionHandle":{backgroundColor:"currentColor",width:"1.5px"},".cm-selectionHandle-start::before, .cm-selectionHandle-end::before":{content:'""',backgroundColor:"inherit",borderRadius:"50%",width:"8px",height:"8px",position:"absolute",left:"-3.25px"},".cm-selectionHandle-start::before":{top:"-8px"},".cm-selectionHandle-end::before":{bottom:"-8px"},".cm-dropCursor":{position:"absolute"},"&.cm-focused > .cm-scroller > .cm-cursorLayer .cm-cursor":{display:"block"},".cm-iso":{unicodeBidi:"isolate"},".cm-announced":{position:"fixed",top:"-10000px"},"@media print":{".cm-announced":{display:"none"}},"&light .cm-activeLine":{backgroundColor:"#cceeff44"},"&dark .cm-activeLine":{backgroundColor:"#99eeff33"},"&light .cm-specialChar":{color:"red"},"&dark .cm-specialChar":{color:"#f78"},".cm-gutters":{flexShrink:0,display:"flex",height:"100%",boxSizing:"border-box",zIndex:200},".cm-gutters-before":{insetInlineStart:0},".cm-gutters-after":{insetInlineEnd:0},"&light .cm-gutters":{backgroundColor:"#f5f5f5",color:"#6c6c6c",border:"0px solid #ddd","&.cm-gutters-before":{borderRightWidth:"1px"},"&.cm-gutters-after":{borderLeftWidth:"1px"}},"&dark .cm-gutters":{backgroundColor:"#333338",color:"#ccc"},".cm-gutter":{display:"flex !important",flexDirection:"column",flexShrink:0,boxSizing:"border-box",minHeight:"100%",overflow:"hidden"},".cm-gutterElement":{boxSizing:"border-box"},".cm-lineNumbers .cm-gutterElement":{padding:"0 3px 0 5px",minWidth:"20px",textAlign:"right",whiteSpace:"nowrap"},"&light .cm-activeLineGutter":{backgroundColor:"#e2f2ff"},"&dark .cm-activeLineGutter":{backgroundColor:"#222227"},".cm-panels":{boxSizing:"border-box",position:"sticky",left:0,right:0,zIndex:300},"&light .cm-panels":{backgroundColor:"#f5f5f5",color:"black"},".cm-panels-top":{top:"0"},".cm-panels-bottom":{bottom:"0"},"&light .cm-panels-top":{borderBottom:"1px solid #ddd"},"&light .cm-panels-bottom":{borderTop:"1px solid #ddd"},"&dark .cm-panels":{backgroundColor:"#333338",color:"white"},".cm-dialog":{padding:"2px 19px 4px 6px",position:"relative","& label":{fontSize:"80%"}},".cm-dialog-close":{position:"absolute",top:"3px",right:"4px",backgroundColor:"inherit",border:"none",font:"inherit",fontSize:"14px",padding:"0"},".cm-tab":{display:"inline-block",overflow:"hidden",verticalAlign:"bottom"},".cm-widgetBuffer":{verticalAlign:"text-top",height:"1em",width:0,display:"inline"},".cm-placeholder":{color:"#888",display:"inline-block",verticalAlign:"top",userSelect:"none"},".cm-highlightSpace":{backgroundImage:"radial-gradient(circle at 50% 55%, #aaa 20%, transparent 5%)",backgroundPosition:"center"},".cm-highlightTab":{backgroundImage:`url('data:image/svg+xml,')`,backgroundSize:"auto 100%",backgroundPosition:"right 90%",backgroundRepeat:"no-repeat"},".cm-trailingSpace":{backgroundColor:"#ff332255"},".cm-button":{verticalAlign:"middle",color:"inherit",fontSize:"70%",padding:".2em 1em",borderRadius:"1px"},"&light .cm-button":{backgroundImage:"linear-gradient(#eff1f5, #d9d9df)",border:"1px solid #888","&:active":{backgroundImage:"linear-gradient(#b4b4b4, #d0d3d6)"}},"&dark .cm-button":{backgroundImage:"linear-gradient(#393939, #111)",border:"1px solid #888","&:active":{backgroundImage:"linear-gradient(#111, #333)"}},".cm-textfield":{verticalAlign:"middle",color:"inherit",fontSize:"70%",border:"1px solid silver",padding:".2em .5em"},"&light .cm-textfield":{backgroundColor:"white"},"&dark .cm-textfield":{border:"1px solid #555",backgroundColor:"inherit"}},Oo),ea={childList:!0,characterData:!0,subtree:!0,attributes:!0,characterDataOldValue:!0},is=w.ie&&w.ie_version<=11;class ia{constructor(t){this.view=t,this.active=!1,this.editContext=null,this.selectionRange=new Pl,this.selectionChanged=!1,this.delayedFlush=-1,this.resizeTimeout=-1,this.queue=[],this.delayedAndroidKey=null,this.flushingAndroidKey=-1,this.lastChange=0,this.scrollTargets=[],this.intersection=null,this.resizeScroll=null,this.intersecting=!1,this.gapIntersection=null,this.gaps=[],this.printQuery=null,this.parentCheck=-1,this.dom=t.contentDOM,this.observer=new MutationObserver(e=>{for(let i of e)this.queue.push(i);(w.ie&&w.ie_version<=11||w.ios&&t.composing)&&e.some(i=>i.type=="childList"&&i.removedNodes.length||i.type=="characterData"&&i.oldValue.length>i.target.nodeValue.length)?this.flushSoon():this.flush()}),window.EditContext&&w.android&&t.constructor.EDIT_CONTEXT!==!1&&!(w.chrome&&w.chrome_version<126)&&(this.editContext=new na(t),t.state.facet(Bt)&&(t.contentDOM.editContext=this.editContext.editContext)),is&&(this.onCharData=e=>{this.queue.push({target:e.target,type:"characterData",oldValue:e.prevValue}),this.flushSoon()}),this.onSelectionChange=this.onSelectionChange.bind(this),this.onResize=this.onResize.bind(this),this.onPrint=this.onPrint.bind(this),this.onScroll=this.onScroll.bind(this),window.matchMedia&&(this.printQuery=window.matchMedia("print")),typeof ResizeObserver=="function"&&(this.resizeScroll=new ResizeObserver(()=>{var e;((e=this.view.docView)===null||e===void 0?void 0:e.lastUpdate){this.parentCheck<0&&(this.parentCheck=setTimeout(this.listenForScroll.bind(this),1e3)),e.length>0&&e[e.length-1].intersectionRatio>0!=this.intersecting&&(this.intersecting=!this.intersecting,this.intersecting!=this.view.inView&&this.onScrollChanged(document.createEvent("Event")))},{threshold:[0,.001]}),this.intersection.observe(this.dom),this.gapIntersection=new IntersectionObserver(e=>{e.length>0&&e[e.length-1].intersectionRatio>0&&this.onScrollChanged(document.createEvent("Event"))},{})),this.listenForScroll(),this.readSelectionRange()}onScrollChanged(t){this.view.inputState.runHandlers("scroll",t),this.intersecting&&this.view.measure()}onScroll(t){this.intersecting&&this.flush(!1),this.editContext&&this.view.requestMeasure(this.editContext.measureReq),this.onScrollChanged(t)}onResize(){this.resizeTimeout<0&&(this.resizeTimeout=setTimeout(()=>{this.resizeTimeout=-1,this.view.requestMeasure()},50))}onPrint(t){(t.type=="change"||!t.type)&&!t.matches||(this.view.viewState.printing=!0,this.view.measure(),setTimeout(()=>{this.view.viewState.printing=!1,this.view.requestMeasure()},500))}updateGaps(t){if(this.gapIntersection&&(t.length!=this.gaps.length||this.gaps.some((e,i)=>e!=t[i]))){this.gapIntersection.disconnect();for(let e of t)this.gapIntersection.observe(e);this.gaps=t}}onSelectionChange(t){let e=this.selectionChanged;if(!this.readSelectionRange()||this.delayedAndroidKey)return;let{view:i}=this,s=this.selectionRange;if(i.state.facet(Bt)?i.root.activeElement!=this.dom:!Ee(this.dom,s))return;let n=s.anchorNode&&i.docView.tile.nearest(s.anchorNode);if(n&&n.isWidget()&&n.widget.ignoreEvent(t)){e||(this.selectionChanged=!1);return}(w.ie&&w.ie_version<=11||w.android&&w.chrome)&&!i.state.selection.main.empty&&s.focusNode&&Ne(s.focusNode,s.focusOffset,s.anchorNode,s.anchorOffset)?this.flushSoon():this.flush(!1)}readSelectionRange(){let{view:t}=this,e=Ke(t.root);if(!e)return!1;let i=w.safari&&t.root.nodeType==11&&t.root.activeElement==this.dom&&sa(this.view,e)||e;if(!i||this.selectionRange.eq(i))return!1;let s=Ee(this.dom,i);return s&&!this.selectionChanged&&t.inputState.lastFocusTime>Date.now()-200&&t.inputState.lastTouchTime{let n=this.delayedAndroidKey;n&&(this.clearDelayedAndroidKey(),this.view.inputState.lastKeyCode=n.keyCode,this.view.inputState.lastKeyTime=Date.now(),!this.flush()&&n.force&&fe(this.dom,n.key,n.keyCode))};this.flushingAndroidKey=this.view.win.requestAnimationFrame(s)}(!this.delayedAndroidKey||t=="Enter")&&(this.delayedAndroidKey={key:t,keyCode:e,force:this.lastChange{this.delayedFlush=-1,this.flush()}))}forceFlush(){this.delayedFlush>=0&&(this.view.win.cancelAnimationFrame(this.delayedFlush),this.delayedFlush=-1),this.flush()}pendingRecords(){for(let t of this.observer.takeRecords())this.queue.push(t);return this.queue}processRecords(){let t=this.pendingRecords();t.length&&(this.queue=[]);let e=-1,i=-1,s=!1;for(let n of t){let o=this.readMutation(n);o&&(o.typeOver&&(s=!0),e==-1?{from:e,to:i}=o:(e=Math.min(o.from,e),i=Math.max(o.to,i)))}return{from:e,to:i,typeOver:s}}readChange(){let{from:t,to:e,typeOver:i}=this.processRecords(),s=this.selectionChanged&&Ee(this.dom,this.selectionRange);if(t<0&&!s)return null;t>-1&&(this.lastChange=Date.now()),this.view.inputState.lastFocusTime=0,this.selectionChanged=!1;let n=new yh(this.view,t,e,i);return this.view.docView.domChanged={newSel:n.newSel?n.newSel.main:null},n}flush(t=!0){if(this.delayedFlush>=0||this.delayedAndroidKey)return!1;t&&this.readSelectionRange();let e=this.readChange();if(!e)return this.view.requestMeasure(),!1;let i=this.view.state,s=co(this.view,e);return this.view.state==i&&(e.domChanged||e.newSel&&!Bi(this.view.state.selection,e.newSel.main))&&this.view.update([]),s}readMutation(t){let e=this.view.docView.tile.nearest(t.target);if(!e||e.isWidget())return null;if(e.markDirty(t.type=="attributes"),t.type=="childList"){let i=tr(e,t.previousSibling||t.target.previousSibling,-1),s=tr(e,t.nextSibling||t.target.nextSibling,1);return{from:i?e.posAfter(i):e.posAtStart,to:s?e.posBefore(s):e.posAtEnd,typeOver:!1}}else return t.type=="characterData"?{from:e.posAtStart,to:e.posAtEnd,typeOver:t.target.nodeValue==t.oldValue}:null}setWindow(t){t!=this.win&&(this.removeWindowListeners(this.win),this.win=t,this.addWindowListeners(this.win))}addWindowListeners(t){t.addEventListener("resize",this.onResize),this.printQuery?this.printQuery.addEventListener?this.printQuery.addEventListener("change",this.onPrint):this.printQuery.addListener(this.onPrint):t.addEventListener("beforeprint",this.onPrint),t.addEventListener("scroll",this.onScroll),t.document.addEventListener("selectionchange",this.onSelectionChange)}removeWindowListeners(t){t.removeEventListener("scroll",this.onScroll),t.removeEventListener("resize",this.onResize),this.printQuery?this.printQuery.removeEventListener?this.printQuery.removeEventListener("change",this.onPrint):this.printQuery.removeListener(this.onPrint):t.removeEventListener("beforeprint",this.onPrint),t.document.removeEventListener("selectionchange",this.onSelectionChange)}update(t){this.editContext&&(this.editContext.update(t),t.startState.facet(Bt)!=t.state.facet(Bt)&&(t.view.contentDOM.editContext=t.state.facet(Bt)?this.editContext.editContext:null))}destroy(){var t,e,i;this.stop(),(t=this.intersection)===null||t===void 0||t.disconnect(),(e=this.gapIntersection)===null||e===void 0||e.disconnect(),(i=this.resizeScroll)===null||i===void 0||i.disconnect();for(let s of this.scrollTargets)s.removeEventListener("scroll",this.onScroll);this.removeWindowListeners(this.win),clearTimeout(this.parentCheck),clearTimeout(this.resizeTimeout),this.win.cancelAnimationFrame(this.delayedFlush),this.win.cancelAnimationFrame(this.flushingAndroidKey),this.editContext&&(this.view.contentDOM.editContext=null,this.editContext.destroy())}}function tr(r,t,e){for(;t;){let i=q.get(t);if(i&&i.parent==r)return i;let s=t.parentNode;t=s!=r.dom?s:e>0?t.nextSibling:t.previousSibling}return null}function er(r,t){let e=t.startContainer,i=t.startOffset,s=t.endContainer,n=t.endOffset,o=r.docView.domAtPos(r.state.selection.main.anchor,1);return Ne(o.node,o.offset,s,n)&&([e,i,s,n]=[s,n,e,i]),{anchorNode:e,anchorOffset:i,focusNode:s,focusOffset:n}}function sa(r,t){if(t.getComposedRanges){let s=t.getComposedRanges(r.root)[0];if(s)return er(r,s)}let e=null;function i(s){s.preventDefault(),s.stopImmediatePropagation(),e=s.getTargetRanges()[0]}return r.contentDOM.addEventListener("beforeinput",i,!0),r.dom.ownerDocument.execCommand("indent"),r.contentDOM.removeEventListener("beforeinput",i,!0),e?er(r,e):null}class na{constructor(t){this.from=0,this.to=0,this.pendingContextChange=null,this.handlers=Object.create(null),this.composing=null,this.resetRange(t.state);let e=this.editContext=new window.EditContext({text:t.state.doc.sliceString(this.from,this.to),selectionStart:this.toContextPos(Math.max(this.from,Math.min(this.to,t.state.selection.main.anchor))),selectionEnd:this.toContextPos(t.state.selection.main.head)});this.handlers.textupdate=i=>{let s=t.state.selection.main,{anchor:n,head:o}=s,l=this.toEditorPos(i.updateRangeStart),h=this.toEditorPos(i.updateRangeEnd);t.inputState.composing>=0&&!this.composing&&(this.composing={contextBase:i.updateRangeStart,editorBase:l,drifted:!1});let a=h-l>i.text.length;l==this.from&&nthis.to&&(h=n);let f=po(t.state.sliceDoc(l,h),i.text,(a?s.from:s.to)-l,a?"end":null);if(!f){let c=k.single(this.toEditorPos(i.selectionStart),this.toEditorPos(i.selectionEnd));Bi(c,s)||t.dispatch({selection:c,userEvent:"select"});return}let u={from:f.from+l,to:f.toA+l,insert:B.of(i.text.slice(f.from,f.toB).split(` +`))};if((w.mac||w.android)&&u.from==o-1&&/^\. ?$/.test(i.text)&&t.contentDOM.getAttribute("autocorrect")=="off"&&(u={from:l,to:h,insert:B.of([i.text.replace("."," ")])}),this.pendingContextChange=u,!t.state.readOnly){let c=this.to-this.from+(u.to-u.from+u.insert.length);tn(t,u,k.single(this.toEditorPos(i.selectionStart,c),this.toEditorPos(i.selectionEnd,c)))}this.pendingContextChange&&(this.revertPending(t.state),this.setSelection(t.state)),u.from=0&&!/[\\p{Alphabetic}\\p{Number}_]/.test(e.text.slice(Math.max(0,i.updateRangeStart-1),Math.min(e.text.length,i.updateRangeStart+1)))&&this.handlers.compositionend(i)},this.handlers.characterboundsupdate=i=>{let s=[],n=null;for(let o=this.toEditorPos(i.rangeStart),l=this.toEditorPos(i.rangeEnd);o{let s=[];for(let n of i.getTextFormats()){let o=n.underlineStyle,l=n.underlineThickness;if(!/none/i.test(o)&&!/none/i.test(l)){let h=this.toEditorPos(n.rangeStart),a=this.toEditorPos(n.rangeEnd);if(h{t.inputState.composing<0&&(t.inputState.composing=0,t.inputState.compositionFirstChange=!0)},this.handlers.compositionend=()=>{if(t.inputState.composing=-1,t.inputState.compositionFirstChange=null,this.composing){let{drifted:i}=this.composing;this.composing=null,i&&this.reset(t.state)}};for(let i in this.handlers)e.addEventListener(i,this.handlers[i]);this.measureReq={read:i=>{let s=Ke(i.root);s&&s.rangeCount&&this.editContext.updateSelectionBounds(s.getRangeAt(0).getBoundingClientRect())}}}applyEdits(t){let e=0,i=!1,s=this.pendingContextChange;return t.changes.iterChanges((n,o,l,h,a)=>{if(i)return;let f=a.length-(o-n);if(s&&o>=s.to)if(s.from==n&&s.to==o&&s.insert.eq(a)){s=this.pendingContextChange=null,e+=f,this.to+=f;return}else s=null,this.revertPending(t.state);if(n+=e,o+=e,o<=this.from)this.from+=f,this.to+=f;else if(nthis.to||this.to-this.from+a.length>3e4){i=!0;return}this.editContext.updateText(this.toContextPos(n),this.toContextPos(o),a.toString()),this.to+=f}e+=f}),s&&!i&&this.revertPending(t.state),!i}update(t){let e=this.pendingContextChange,i=t.startState.selection.main;this.composing&&(this.composing.drifted||!t.changes.touchesRange(i.from,i.to)&&t.transactions.some(s=>!s.isUserEvent("input.type")&&s.changes.touchesRange(this.from,this.to)))?(this.composing.drifted=!0,this.composing.editorBase=t.changes.mapPos(this.composing.editorBase)):!this.applyEdits(t)||!this.rangeIsValid(t.state)?(this.pendingContextChange=null,this.reset(t.state)):(t.docChanged||t.selectionSet||e)&&this.setSelection(t.state),(t.geometryChanged||t.docChanged||t.selectionSet)&&t.view.requestMeasure(this.measureReq)}resetRange(t){let{head:e}=t.selection.main;this.from=Math.max(0,e-1e4),this.to=Math.min(t.doc.length,e+1e4)}reset(t){this.resetRange(t),this.editContext.updateText(0,this.editContext.text.length,t.doc.sliceString(this.from,this.to)),this.setSelection(t)}revertPending(t){let e=this.pendingContextChange;this.pendingContextChange=null,this.editContext.updateText(this.toContextPos(e.from),this.toContextPos(e.from+e.insert.length),t.doc.sliceString(e.from,e.to))}setSelection(t){let{main:e}=t.selection,i=this.toContextPos(Math.max(this.from,Math.min(this.to,e.anchor))),s=this.toContextPos(e.head);(this.editContext.selectionStart!=i||this.editContext.selectionEnd!=s)&&this.editContext.updateSelection(i,s)}rangeIsValid(t){let{head:e}=t.selection.main;return!(this.from>0&&e-this.from<500||this.to1e4*3)}toEditorPos(t,e=this.to-this.from){t=Math.min(t,e);let i=this.composing;return i&&i.drifted?i.editorBase+(t-i.contextBase):t+this.from}toContextPos(t){let e=this.composing;return e&&e.drifted?e.contextBase+(t-e.editorBase):t-this.from}destroy(){for(let t in this.handlers)this.editContext.removeEventListener(t,this.handlers[t])}}class D{get state(){return this.viewState.state}get viewport(){return this.viewState.viewport}get visibleRanges(){return this.viewState.visibleRanges}get inView(){return this.viewState.inView}get composing(){return!!this.inputState&&this.inputState.composing>0}get compositionStarted(){return!!this.inputState&&this.inputState.composing>=0}get root(){return this._root}get win(){return this.dom.ownerDocument.defaultView||window}constructor(t={}){var e;this.plugins=[],this.pluginMap=new Map,this.editorAttrs={},this.contentAttrs={},this.bidiCache=[],this.destroyed=!1,this.updateState=2,this.measureScheduled=-1,this.measureRequests=[],this.contentDOM=document.createElement("div"),this.scrollDOM=document.createElement("div"),this.scrollDOM.tabIndex=-1,this.scrollDOM.className="cm-scroller",this.scrollDOM.appendChild(this.contentDOM),this.announceDOM=document.createElement("div"),this.announceDOM.className="cm-announced",this.announceDOM.setAttribute("aria-live","polite"),this.dom=document.createElement("div"),this.dom.appendChild(this.announceDOM),this.dom.appendChild(this.scrollDOM),t.parent&&t.parent.appendChild(this.dom);let{dispatch:i}=t;this.dispatchTransactions=t.dispatchTransactions||i&&(s=>s.forEach(n=>i(n,this)))||(s=>this.update(s)),this.dispatch=this.dispatch.bind(this),this._root=t.root||Dl(t.parent)||document,this.viewState=new _n(this,t.state||I.create(t)),t.scrollTo&&t.scrollTo.is(si)&&(this.viewState.scrollTarget=t.scrollTo.value.clip(this.viewState.state)),this.plugins=this.state.facet(oe).map(s=>new Xi(s));for(let s of this.plugins)s.update(this);this.observer=new ia(this),this.inputState=new Ch(this),this.inputState.ensureHandlers(this.plugins),this.docView=new Fn(this),this.mountStyles(),this.updateAttrs(),this.updateState=0,this.requestMeasure(),!((e=document.fonts)===null||e===void 0)&&e.ready&&document.fonts.ready.then(()=>{this.viewState.mustMeasureContent="refresh",this.requestMeasure()})}dispatch(...t){let e=t.length==1&&t[0]instanceof tt?t:t.length==1&&Array.isArray(t[0])?t[0]:[this.state.update(...t)];this.dispatchTransactions(e,this)}update(t){if(this.updateState!=0)throw new Error("Calls to EditorView.update are not allowed while an update is in progress");let e=!1,i=!1,s,n=this.state;for(let c of t){if(c.startState!=n)throw new RangeError("Trying to update state with a transaction that doesn't start from the previous state.");n=c.state}if(this.destroyed){this.viewState.state=n;return}let o=this.hasFocus,l=0,h=null;t.some(c=>c.annotation(yo))?(this.inputState.notifiedFocused=o,l=1):o!=this.inputState.notifiedFocused&&(this.inputState.notifiedFocused=o,h=ko(n,o),h||(l=1));let a=this.observer.delayedAndroidKey,f=null;if(a?(this.observer.clearDelayedAndroidKey(),f=this.observer.readChange(),(f&&!this.state.doc.eq(n.doc)||!this.state.selection.eq(n.selection))&&(f=null)):this.observer.clear(),n.facet(I.phrases)!=this.state.facet(I.phrases))return this.setState(n);s=Mi.create(this,n,t),s.flags|=l;let u=this.viewState.scrollTarget;try{this.updateState=2;for(let c of t){if(u&&(u=u.map(c.changes)),c.scrollIntoView){let{main:d}=c.state.selection,{x:p,y:g}=this.state.facet(D.cursorScrollMargin);u=new ue(d.empty?d:k.cursor(d.head,d.head>d.anchor?-1:1),"nearest","nearest",g,p)}for(let d of c.effects)d.is(si)&&(u=d.value.clip(this.state))}this.viewState.update(s,u),this.bidiCache=Ei.update(this.bidiCache,s.changes),s.empty||(this.updatePlugins(s),this.inputState.update(s)),e=this.docView.update(s),this.state.facet(Te)!=this.styleModules&&this.mountStyles(),i=this.updateAttrs(),this.showAnnouncements(t),this.docView.updateSelection(e,t.some(c=>c.isUserEvent("select.pointer")))}finally{this.updateState=0}if(s.startState.facet(ai)!=s.state.facet(ai)&&(this.viewState.mustMeasureContent=!0),(e||i||u||this.viewState.mustEnforceCursorAssoc||this.viewState.mustMeasureContent)&&this.requestMeasure(),e&&this.docViewUpdate(),!s.empty)for(let c of this.state.facet(Ds))try{c(s)}catch(d){Tt(this.state,d,"update listener")}(h||f)&&Promise.resolve().then(()=>{h&&this.state==h.startState&&this.dispatch(h),f&&!co(this,f)&&a.force&&fe(this.contentDOM,a.key,a.keyCode)})}setState(t){if(this.updateState!=0)throw new Error("Calls to EditorView.setState are not allowed while an update is in progress");if(this.destroyed){this.viewState.state=t;return}this.updateState=2;let e=this.hasFocus;try{for(let i of this.plugins)i.destroy(this);this.viewState=new _n(this,t),this.plugins=t.facet(oe).map(i=>new Xi(i)),this.pluginMap.clear();for(let i of this.plugins)i.update(this);this.docView.destroy(),this.docView=new Fn(this),this.inputState.ensureHandlers(this.plugins),this.mountStyles(),this.updateAttrs(),this.bidiCache=[]}finally{this.updateState=0}e&&this.focus(),this.requestMeasure()}updatePlugins(t){let e=t.startState.facet(oe),i=t.state.facet(oe);if(e!=i){let s=[];for(let n of i){let o=e.indexOf(n);if(o<0)s.push(new Xi(n));else{let l=this.plugins[o];l.mustUpdate=t,s.push(l)}}for(let n of this.plugins)n.mustUpdate!=t&&n.destroy(this);this.plugins=s,this.pluginMap.clear()}else for(let s of this.plugins)s.mustUpdate=t;for(let s=0;s-1&&this.win.cancelAnimationFrame(this.measureScheduled),this.observer.delayedAndroidKey){this.measureScheduled=-1,this.requestMeasure();return}this.measureScheduled=0,t&&this.observer.forceFlush();let e=null,i=this.viewState.scrollParent,s=this.viewState.getScrollOffset(),{scrollAnchorPos:n,scrollAnchorHeight:o}=this.viewState;Math.abs(s-this.viewState.scrollOffset)>1&&(o=-1),this.viewState.scrollAnchorHeight=-1;try{for(let l=0;;l++){if(o<0)if(Vr(i||this.win))n=-1,o=this.viewState.heightMap.height;else{let d=this.viewState.scrollAnchorAt(s);n=d.from,o=d.top}this.updateState=1;let h=this.viewState.measure();if(!h&&!this.measureRequests.length&&this.viewState.scrollTarget==null)break;if(l>5){console.warn(this.measureRequests.length?"Measure loop restarted more than 5 times":"Viewport failed to stabilize");break}let a=[];h&4||([this.measureRequests,a]=[a,this.measureRequests]);let f=a.map(d=>{try{return d.read(this)}catch(p){return Tt(this.state,p),ir}}),u=Mi.create(this,this.state,[]),c=!1;u.flags|=h,e?e.flags|=h:e=u,this.updateState=2,u.empty||(this.updatePlugins(u),this.inputState.update(u),this.updateAttrs(),c=this.docView.update(u),c&&this.docViewUpdate());for(let d=0;d1||p<-1)&&!(w.ios&&this.inputState.lastIOSMomentumScroll>Date.now()-100)&&(i==this.scrollDOM||this.hasFocus||Math.max(this.inputState.lastWheelEvent,this.inputState.lastTouchTime)>Date.now()-100)){s=s+p,i?i.scrollTop+=p:this.win.scrollBy(0,p),o=-1;continue}}break}}}finally{this.updateState=0,this.measureScheduled=-1}if(e&&!e.empty)for(let l of this.state.facet(Ds))l(e)}get themeClasses(){return Is+" "+(this.state.facet(Ns)?Ao:Co)+" "+this.state.facet(ai)}updateAttrs(){let t=sr(this,so,{class:"cm-editor"+(this.hasFocus?" cm-focused ":" ")+this.themeClasses}),e={spellcheck:"false",autocorrect:"off",autocapitalize:"off",writingsuggestions:"false",translate:"no",contenteditable:this.state.facet(Bt)?"true":"false",class:"cm-content",style:`${w.tabSize}: ${this.state.tabSize}`,role:"textbox","aria-multiline":"true"};this.state.readOnly&&(e["aria-readonly"]="true"),sr(this,Js,e);let i=this.observer.ignore(()=>{let s=Rn(this.contentDOM,this.contentAttrs,e),n=Rn(this.dom,this.editorAttrs,t);return s||n});return this.editorAttrs=t,this.contentAttrs=e,i}showAnnouncements(t){let e=!0;for(let i of t)for(let s of i.effects)if(s.is(D.announce)){e&&(this.announceDOM.textContent=""),e=!1;let n=this.announceDOM.appendChild(document.createElement("div"));n.textContent=s.value}}mountStyles(){this.styleModules=this.state.facet(Te);let t=this.state.facet(D.cspNonce);de.mount(this.root,this.styleModules.concat(ta).reverse(),t?{nonce:t}:void 0)}readMeasured(){if(this.updateState==2)throw new Error("Reading the editor layout isn't allowed during an update");this.updateState==0&&this.measureScheduled>-1&&this.measure(!1)}requestMeasure(t){if(this.measureScheduled<0&&(this.measureScheduled=this.win.requestAnimationFrame(()=>this.measure())),t){if(this.measureRequests.indexOf(t)>-1)return;if(t.key!=null){for(let e=0;ei.plugin==t)||null),e&&e.update(this).value}get documentTop(){return this.contentDOM.getBoundingClientRect().top+this.viewState.paddingTop}get documentPadding(){return{top:this.viewState.paddingTop,bottom:this.viewState.paddingBottom}}get scaleX(){return this.viewState.scaleX}get scaleY(){return this.viewState.scaleY}elementAtHeight(t){return this.readMeasured(),this.viewState.elementAtHeight(t)}lineBlockAtHeight(t){return this.readMeasured(),this.viewState.lineBlockAtHeight(t)}get viewportLineBlocks(){return this.viewState.viewportLines}lineBlockAt(t){return this.viewState.lineBlockAt(t)}get contentHeight(){return this.viewState.contentHeight}moveByChar(t,e,i){return ts(this,t,Hn(this,t,e,i))}moveByGroup(t,e){return ts(this,t,Hn(this,t,e,i=>ph(this,t.head,i)))}visualLineSide(t,e){let i=this.bidiSpans(t),s=this.textDirectionAt(t.from),n=i[e?i.length-1:0];return k.cursor(n.side(e,s)+t.from,n.forward(!e,s)?1:-1)}moveToLineBoundary(t,e,i=!0){return dh(this,t,e,i)}moveVertically(t,e,i){return ts(this,t,gh(this,t,e,i))}domAtPos(t,e=1){return this.docView.domAtPos(t,e)}posAtDOM(t,e=0){return this.docView.posFromDOM(t,e)}posAtCoords(t,e=!0){this.readMeasured();let i=Rs(this,t,e);return i&&i.pos}posAndSideAtCoords(t,e=!0){return this.readMeasured(),Rs(this,t,e)}coordsAtPos(t,e=1){this.readMeasured();let i=this.state.doc.lineAt(t),s=this.bidiSpans(i),n=s[Ot.find(s,t-i.from,-1,e)];return this.docView.coordsAt(t,e,n.dir==G.RTL)}coordsForChar(t){return this.readMeasured(),this.docView.coordsForChar(t)}get defaultCharacterWidth(){return this.viewState.heightOracle.charWidth}get defaultLineHeight(){return this.viewState.heightOracle.lineHeight}get textDirection(){return this.viewState.defaultTextDirection}textDirectionAt(t){return!this.state.facet(to)||tthis.viewport.to?this.textDirection:(this.readMeasured(),this.docView.textDirectionAt(t))}get lineWrapping(){return this.viewState.heightOracle.lineWrapping}bidiSpans(t){if(t.length>ra)return Qr(t.length);let e=this.textDirectionAt(t.from),i;for(let n of this.bidiCache)if(n.from==t.from&&n.dir==e&&(n.fresh||jr(n.isolates,i=In(this,t))))return n.order;i||(i=In(this,t));let s=Fl(t.text,e,i);return this.bidiCache.push(new Ei(t.from,t.to,e,i,!0,s)),s}get hasFocus(){var t;return(this.dom.ownerDocument.hasFocus()||w.safari&&((t=this.inputState)===null||t===void 0?void 0:t.lastContextMenu)>Date.now()-3e4)&&this.root.activeElement==this.contentDOM}focus(){this.observer.ignore(()=>{Hr(this.contentDOM),this.docView.updateSelection()})}setRoot(t){this._root!=t&&(this._root=t,this.observer.setWindow((t.nodeType==9?t:t.ownerDocument).defaultView||window),this.mountStyles())}destroy(){this.root.activeElement==this.contentDOM&&this.contentDOM.blur();for(let t of this.plugins)t.destroy(this);this.plugins=[],this.inputState.destroy(),this.docView.destroy(),this.dom.remove(),this.observer.destroy(),this.measureScheduled>-1&&this.win.cancelAnimationFrame(this.measureScheduled),this.destroyed=!0}static scrollIntoView(t,e={}){var i,s,n,o;return si.of(new ue(typeof t=="number"?k.cursor(t):t,(i=e.y)!==null&&i!==void 0?i:"nearest",(s=e.x)!==null&&s!==void 0?s:"nearest",(n=e.yMargin)!==null&&n!==void 0?n:5,(o=e.xMargin)!==null&&o!==void 0?o:5))}scrollSnapshot(){let{scrollTop:t,scrollLeft:e}=this.scrollDOM,i=this.viewState.scrollAnchorAt(t);return si.of(new ue(k.cursor(i.from),"start","start",i.top-t,e,!0))}setTabFocusMode(t){t==null?this.inputState.tabFocusMode=this.inputState.tabFocusMode<0?0:-1:typeof t=="boolean"?this.inputState.tabFocusMode=t?0:-1:this.inputState.tabFocusMode!=0&&(this.inputState.tabFocusMode=Date.now()+t)}static domEventHandlers(t){return pe.define(()=>({}),{eventHandlers:t})}static domEventObservers(t){return pe.define(()=>({}),{eventObservers:t})}static theme(t,e){let i=de.newName(),s=[ai.of(i),Te.of(Ls(`.${i}`,t))];return e&&e.dark&&s.push(Ns.of(!0)),s}static baseTheme(t){return Cr.lowest(Te.of(Ls("."+Is,t,Oo)))}static findFromDOM(t){var e;let i=t.querySelector(".cm-content"),s=i&&q.get(i)||q.get(t);return((e=s?.root)===null||e===void 0?void 0:e.view)||null}}D.styleModule=Te;D.inputHandler=Jr;D.clipboardInputFilter=Xs;D.clipboardOutputFilter=_s;D.scrollHandler=eo;D.focusChangeEffect=Zr;D.perLineTextDirection=to;D.exceptionSink=_r;D.updateListener=Ds;D.editable=Bt;D.mouseSelectionStyle=Xr;D.dragMovesSelection=Yr;D.clickAddsSelectionRange=Gr;D.decorations=Hi;D.blockWrappers=no;D.outerDecorations=Zs;D.atomicRanges=Qe;D.bidiIsolatedRanges=ro;D.cursorScrollMargin=M.define({combine:r=>{let t=5,e=5;for(let i of r)typeof i=="number"?t=e=i:{x:t,y:e}=i;return{x:t,y:e}}});D.scrollMargins=oo;D.darkTheme=Ns;D.cspNonce=M.define({combine:r=>r.length?r[0]:""});D.contentAttributes=Js;D.editorAttributes=so;D.lineWrapping=D.contentAttributes.of({class:"cm-lineWrapping"});D.announce=U.define();const ra=4096,ir={};class Ei{constructor(t,e,i,s,n,o){this.from=t,this.to=e,this.dir=i,this.isolates=s,this.fresh=n,this.order=o}static update(t,e){if(e.empty&&!t.some(n=>n.fresh))return t;let i=[],s=t.length?t[t.length-1].dir:G.LTR;for(let n=Math.max(0,t.length-10);n=0;s--){let n=i[s],o=typeof n=="function"?n(r):n;o&&Us(o,e)}return e}const oa=w.mac?"mac":w.windows?"win":w.linux?"linux":"key";function la(r,t){const e=r.split(/-(?!$)/);let i=e[e.length-1];i=="Space"&&(i=" ");let s,n,o,l;for(let h=0;hi.concat(s),[]))),e}let Vt=null;const ua=4e3;function ca(r,t=oa){let e=Object.create(null),i=Object.create(null),s=(o,l)=>{let h=i[o];if(h==null)i[o]=l;else if(h!=l)throw new Error("Key binding "+o+" is used both as a regular binding and as a multi-stroke prefix")},n=(o,l,h,a,f)=>{var u,c;let d=e[o]||(e[o]=Object.create(null)),p=l.split(/ (?!$)/).map(b=>la(b,t));for(let b=1;b{let E=Vt={view:v,prefix:y,scope:o};return setTimeout(()=>{Vt==E&&(Vt=null)},ua),!0}]})}let g=p.join(" ");s(g,!1);let m=d[g]||(d[g]={preventDefault:!1,stopPropagation:!1,run:((c=(u=d._any)===null||u===void 0?void 0:u.run)===null||c===void 0?void 0:c.slice())||[]});h&&m.run.push(h),a&&(m.preventDefault=!0),f&&(m.stopPropagation=!0)};for(let o of r){let l=o.scope?o.scope.split(" "):["editor"];if(o.any)for(let a of l){let f=e[a]||(e[a]=Object.create(null));f._any||(f._any={preventDefault:!1,stopPropagation:!1,run:[]});let{any:u}=o;for(let c in f)f[c].run.push(d=>u(d,Ws))}let h=o[t]||o.key;if(h)for(let a of l)n(a,h,o.run,o.preventDefault,o.stopPropagation),o.shift&&n(a,"Shift-"+h,o.shift,o.preventDefault,o.stopPropagation)}return e}let Ws=null;function da(r,t,e,i){Ws=t;let s=vl(t),n=rl(s,0),o=ol(n)==s.length&&s!=" ",l="",h=!1,a=!1,f=!1;Vt&&Vt.view==e&&Vt.scope==i&&(l=Vt.prefix+" ",mo.indexOf(t.keyCode)<0&&(a=!0,Vt=null));let u=new Set,c=m=>{if(m){for(let b of m.run)if(!u.has(b)&&(u.add(b),b(e)))return m.stopPropagation&&(f=!0),!0;m.preventDefault&&(m.stopPropagation&&(f=!0),a=!0)}return!1},d=r[i],p,g;return d&&(c(d[l+fi(s,t,!o)])?h=!0:o&&(t.altKey||t.metaKey||t.ctrlKey)&&!(w.windows&&t.ctrlKey&&t.altKey)&&!(w.mac&&t.altKey&&!(t.ctrlKey||t.metaKey))&&(p=qt[t.keyCode])&&p!=s?(c(d[l+fi(p,t,!0)])||t.shiftKey&&(g=Ve[t.keyCode])!=s&&g!=p&&c(d[l+fi(g,t,!1)]))&&(h=!0):o&&t.shiftKey&&c(d[l+fi(s,t,!0)])&&(h=!0),!h&&c(d._any)&&(h=!0)),a&&(h=!0),h&&f&&t.stopPropagation(),Ws=null,h}class xe extends Zt{compare(t){return this==t||this.constructor==t.constructor&&this.eq(t)}eq(t){return!1}destroy(t){}}xe.prototype.elementClass="";xe.prototype.toDOM=void 0;xe.prototype.mapMode=at.TrackBefore;xe.prototype.startSide=xe.prototype.endSide=-1;xe.prototype.point=!0;var ss;const Pe=new R;function pa(r){return M.define({combine:r?t=>t.concat(r):void 0})}const ga=new R;class Mt{constructor(t,e,i=[],s=""){this.data=t,this.name=s,I.prototype.hasOwnProperty("tree")||Object.defineProperty(I.prototype,"tree",{get(){return Fs(this)}}),this.parser=e,this.extension=[ye.of(this),I.languageData.of((n,o,l)=>{let h=rr(n,o,l),a=h.type.prop(Pe);if(!a)return[];let f=n.facet(a),u=h.type.prop(ga);if(u){let c=h.resolve(o-h.from,l);for(let d of u)if(d.test(c,n)){let p=n.facet(d.facet);return d.type=="replace"?p:p.concat(f)}}return f})].concat(i)}isActiveAt(t,e,i=-1){return rr(t,e,i).type.prop(Pe)==this.data}findRegions(t){let e=t.facet(ye);if(e?.data==this.data)return[{from:0,to:t.doc.length}];if(!e||!e.allowsNesting)return[];let i=[],s=(n,o)=>{if(n.prop(Pe)==this.data){i.push({from:o,to:o+n.length});return}let l=n.prop(R.mounted);if(l){if(l.tree.prop(Pe)==this.data){if(l.overlay)for(let h of l.overlay)i.push({from:h.from+o,to:h.to+o});else i.push({from:o,to:o+n.length});return}else if(l.overlay){let h=i.length;if(s(l.tree,l.overlay[0].from+o),i.length>h)return}}for(let h=0;hi.isTop?e:void 0)]}),t.name)}configure(t,e){return new Ni(this.data,this.parser.configure(t),e||this.name)}get allowsNesting(){return this.parser.hasWrappers()}}function Fs(r){let t=r.field(Mt.state,!1);return t?t.tree:Q.empty}class ma{constructor(t){this.doc=t,this.cursorPos=0,this.string="",this.cursor=t.iter()}get length(){return this.doc.length}syncTo(t){return this.string=this.cursor.next(t-this.cursorPos).value,this.cursorPos=t+this.string.length,this.cursorPos-this.string.length}chunk(t){return this.syncTo(t),this.string}get lineChunks(){return!0}read(t,e){let i=this.cursorPos-this.string.length;return t=this.cursorPos?this.doc.sliceString(t,e):this.string.slice(t-i,e-i)}}let Oe=null;class Ii{constructor(t,e,i=[],s,n,o,l,h){this.parser=t,this.state=e,this.fragments=i,this.tree=s,this.treeLen=n,this.viewport=o,this.skipped=l,this.scheduleOn=h,this.parse=null,this.tempSkipped=[]}static create(t,e,i){return new Ii(t,e,[],Q.empty,0,i,[],null)}startParse(){return this.parser.startParse(new ma(this.state.doc),this.fragments)}work(t,e){return e!=null&&e>=this.state.doc.length&&(e=void 0),this.tree!=Q.empty&&this.isDone(e??this.state.doc.length)?(this.takeTree(),!0):this.withContext(()=>{var i;if(typeof t=="number"){let s=Date.now()+t;t=()=>Date.now()>s}for(this.parse||(this.parse=this.startParse()),e!=null&&(this.parse.stoppedAt==null||this.parse.stoppedAt>e)&&e=this.treeLen&&((this.parse.stoppedAt==null||this.parse.stoppedAt>t)&&this.parse.stopAt(t),this.withContext(()=>{for(;!(e=this.parse.advance()););}),this.treeLen=t,this.tree=e,this.fragments=this.withoutTempSkipped(Jt.addTree(this.tree,this.fragments,!0)),this.parse=null)}withContext(t){let e=Oe;Oe=this;try{return t()}finally{Oe=e}}withoutTempSkipped(t){for(let e;e=this.tempSkipped.pop();)t=or(t,e.from,e.to);return t}changes(t,e){let{fragments:i,tree:s,treeLen:n,viewport:o,skipped:l}=this;if(this.takeTree(),!t.empty){let h=[];if(t.iterChangedRanges((a,f,u,c)=>h.push({fromA:a,toA:f,fromB:u,toB:c})),i=Jt.applyChanges(i,h),s=Q.empty,n=0,o={from:t.mapPos(o.from,-1),to:t.mapPos(o.to,1)},this.skipped.length){l=[];for(let a of this.skipped){let f=t.mapPos(a.from,1),u=t.mapPos(a.to,-1);ft.from&&(this.fragments=or(this.fragments,s,n),this.skipped.splice(i--,1))}return this.skipped.length>=e?!1:(this.reset(),!0)}reset(){this.parse&&(this.takeTree(),this.parse=null)}skipUntilInView(t,e){this.skipped.push({from:t,to:e})}static getSkippingParser(t){return new class extends pr{createParse(e,i,s){let n=s[0].from,o=s[s.length-1].to;return{parsedPos:n,advance(){let h=Oe;if(h){for(let a of s)h.tempSkipped.push(a);t&&(h.scheduleOn=h.scheduleOn?Promise.all([h.scheduleOn,t]):t)}return this.parsedPos=o,new Q(ot.none,[],[],o-n)},stoppedAt:null,stopAt(){}}}}}isDone(t){t=Math.min(t,this.state.doc.length);let e=this.fragments;return this.treeLen>=t&&e.length&&e[0].from==0&&e[0].to>=t}static get(){return Oe}}function or(r,t,e){return Jt.applyChanges(r,[{fromA:t,toA:e,fromB:t,toB:e}])}class we{constructor(t){this.context=t,this.tree=t.tree}apply(t){if(!t.docChanged&&this.tree==this.context.tree)return this;let e=this.context.changes(t.changes,t.state),i=this.context.treeLen==t.startState.doc.length?void 0:Math.max(t.changes.mapPos(this.context.treeLen),e.viewport.to);return e.work(20,i)||e.takeTree(),new we(e)}static init(t){let e=Math.min(3e3,t.doc.length),i=Ii.create(t.facet(ye).parser,t,{from:0,to:e});return i.work(20,e)||i.takeTree(),new we(i)}}Mt.state=se.define({create:we.init,update(r,t){for(let e of t.effects)if(e.is(Mt.setState))return e.value;return t.startState.facet(ye)!=t.state.facet(ye)?we.init(t.state):r.apply(t)}});let To=r=>{let t=setTimeout(()=>r(),500);return()=>clearTimeout(t)};typeof requestIdleCallback<"u"&&(To=r=>{let t=-1,e=setTimeout(()=>{t=requestIdleCallback(r,{timeout:400})},100);return()=>t<0?clearTimeout(e):cancelIdleCallback(t)});const ns=typeof navigator<"u"&&(!((ss=navigator.scheduling)===null||ss===void 0)&&ss.isInputPending)?()=>navigator.scheduling.isInputPending():null,ba=pe.fromClass(class{constructor(t){this.view=t,this.working=null,this.workScheduled=0,this.chunkEnd=-1,this.chunkBudget=-1,this.work=this.work.bind(this),this.scheduleWork()}update(t){let e=this.view.state.field(Mt.state).context;(e.updateViewport(t.view.viewport)||this.view.viewport.to>e.treeLen)&&this.scheduleWork(),(t.docChanged||t.selectionSet)&&(this.view.hasFocus&&(this.chunkBudget+=50),this.scheduleWork()),this.checkAsyncSchedule(e)}scheduleWork(){if(this.working)return;let{state:t}=this.view,e=t.field(Mt.state);(e.tree!=e.context.tree||!e.context.isDone(t.doc.length))&&(this.working=To(this.work))}work(t){this.working=null;let e=Date.now();if(this.chunkEnds+1e3,h=n.context.work(()=>ns&&ns()||Date.now()>o,s+(l?0:1e5));this.chunkBudget-=Date.now()-e,(h||this.chunkBudget<=0)&&(n.context.takeTree(),this.view.dispatch({effects:Mt.setState.of(new we(n.context))})),this.chunkBudget>0&&!(h&&!l)&&this.scheduleWork(),this.checkAsyncSchedule(n.context)}checkAsyncSchedule(t){t.scheduleOn&&(this.workScheduled++,t.scheduleOn.then(()=>this.scheduleWork()).catch(e=>Tt(this.view.state,e)).then(()=>this.workScheduled--),t.scheduleOn=null)}destroy(){this.working&&this.working()}isWorking(){return!!(this.working||this.workScheduled>0)}},{eventHandlers:{focus(){this.scheduleWork()}}}),ye=M.define({combine(r){return r.length?r[0]:null},enables:r=>[Mt.state,ba,D.contentAttributes.compute([r],t=>{let e=t.facet(r);return e&&e.name?{"data-language":e.name}:{}})]});class xa{constructor(t,e=[]){this.language=t,this.support=e,this.extension=[t,e]}}const wa=new R;function lr({except:r,units:t=1}={}){return e=>{let i=r&&r.test(e.textAfter);return e.baseIndent+(i?0:t*e.unit)}}const ya=new R;function ka(r){let t=r.firstChild,e=r.lastChild;return t&&t.to-1||(ar.push(r),console.warn(t))}function Ca(r,t){let e=[];for(let l of t.split(" ")){let h=[];for(let a of l.split(".")){let f=r[a]||A[a];f?typeof f=="function"?h.length?h=h.map(f):rs(a,`Modifier ${a} used at start of tag`):h.length?rs(a,`Tag ${a} used as modifier`):h=Array.isArray(f)?f:[f]:rs(a,`Unknown highlighting tag ${a}`)}for(let a of h)e.push(a)}if(!e.length)return 0;let i=t.replace(/ /g,"_"),s=i+" "+e.map(l=>l.id),n=fr[s];if(n)return n.id;let o=fr[s]=ot.define({id:hr.length,name:i,props:[gr({[i]:e})]});return hr.push(o),o.id}G.RTL,G.LTR;const Aa=Ni.define({name:"json",parser:_o.configure({props:[wa.add({Object:lr({except:/^\s*\}/}),Array:lr({except:/^\s*\]/})}),ya.add({"Object Array":ka})]}),languageData:{closeBrackets:{brackets:["[","{",'"']},indentOnInput:/^\s*[\}\]]$/}});function Pa(){return new xa(Aa)}export{D as E,I as a,Pa as j,aa as k}; diff --git a/src/runtime/operator/web_assets/assets/graph-Dj7zaIMl.js b/src/runtime/operator/web_assets/assets/graph-Dj7zaIMl.js new file mode 100644 index 0000000..cb0eab0 --- /dev/null +++ b/src/runtime/operator/web_assets/assets/graph-Dj7zaIMl.js @@ -0,0 +1,7 @@ +function Hr(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var yn={exports:{}},st={};var _o;function Ma(){if(_o)return st;_o=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.fragment");function n(o,r,i){var s=null;if(i!==void 0&&(s=""+i),r.key!==void 0&&(s=""+r.key),"key"in r){i={};for(var a in r)a!=="key"&&(i[a]=r[a])}else i=r;return r=i.ref,{$$typeof:e,type:o,key:s,ref:r!==void 0?r:null,props:i}}return st.Fragment=t,st.jsx=n,st.jsxs=n,st}var Eo;function Aa(){return Eo||(Eo=1,yn.exports=Ma()),yn.exports}var R=Aa(),xn={exports:{}},K={};var bo;function Ia(){if(bo)return K;bo=1;var e=Symbol.for("react.transitional.element"),t=Symbol.for("react.portal"),n=Symbol.for("react.fragment"),o=Symbol.for("react.strict_mode"),r=Symbol.for("react.profiler"),i=Symbol.for("react.consumer"),s=Symbol.for("react.context"),a=Symbol.for("react.forward_ref"),u=Symbol.for("react.suspense"),c=Symbol.for("react.memo"),l=Symbol.for("react.lazy"),f=Symbol.for("react.activity"),d=Symbol.iterator;function h(m){return m===null||typeof m!="object"?null:(m=d&&m[d]||m["@@iterator"],typeof m=="function"?m:null)}var g={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},_=Object.assign,w={};function y(m,E,V){this.props=m,this.context=E,this.refs=w,this.updater=V||g}y.prototype.isReactComponent={},y.prototype.setState=function(m,E){if(typeof m!="object"&&typeof m!="function"&&m!=null)throw Error("takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,m,E,"setState")},y.prototype.forceUpdate=function(m){this.updater.enqueueForceUpdate(this,m,"forceUpdate")};function C(){}C.prototype=y.prototype;function p(m,E,V){this.props=m,this.context=E,this.refs=w,this.updater=V||g}var v=p.prototype=new C;v.constructor=p,_(v,y.prototype),v.isPureReactComponent=!0;var A=Array.isArray;function S(){}var b={H:null,A:null,T:null,S:null},T=Object.prototype.hasOwnProperty;function k(m,E,V){var L=V.ref;return{$$typeof:e,type:m,key:E,ref:L!==void 0?L:null,props:V}}function F(m,E){return k(m.type,E,m.props)}function z(m){return typeof m=="object"&&m!==null&&m.$$typeof===e}function B(m){var E={"=":"=0",":":"=2"};return"$"+m.replace(/[=:]/g,function(V){return E[V]})}var O=/\/+/g;function x(m,E){return typeof m=="object"&&m!==null&&m.key!=null?B(""+m.key):E.toString(36)}function M(m){switch(m.status){case"fulfilled":return m.value;case"rejected":throw m.reason;default:switch(typeof m.status=="string"?m.then(S,S):(m.status="pending",m.then(function(E){m.status==="pending"&&(m.status="fulfilled",m.value=E)},function(E){m.status==="pending"&&(m.status="rejected",m.reason=E)})),m.status){case"fulfilled":return m.value;case"rejected":throw m.reason}}throw m}function N(m,E,V,L,Y){var W=typeof m;(W==="undefined"||W==="boolean")&&(m=null);var Z=!1;if(m===null)Z=!0;else switch(W){case"bigint":case"string":case"number":Z=!0;break;case"object":switch(m.$$typeof){case e:case t:Z=!0;break;case l:return Z=m._init,N(Z(m._payload),E,V,L,Y)}}if(Z)return Y=Y(m),Z=L===""?"."+x(m,0):L,A(Y)?(V="",Z!=null&&(V=Z.replace(O,"$&/")+"/"),N(Y,E,V,"",function(J){return J})):Y!=null&&(z(Y)&&(Y=F(Y,V+(Y.key==null||m&&m.key===Y.key?"":(""+Y.key).replace(O,"$&/")+"/")+Z)),E.push(Y)),1;Z=0;var H=L===""?".":L+":";if(A(m))for(var X=0;X"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}return e(),wn.exports=ka(),wn.exports}function se(e){if(typeof e=="string"||typeof e=="number")return""+e;let t="";if(Array.isArray(e))for(let n=0,o;n{}};function tn(){for(var e=0,t=arguments.length,n={},o;e=0&&(o=n.slice(r+1),n=n.slice(0,r)),n&&!t.hasOwnProperty(n))throw new Error("unknown type: "+n);return{type:n,name:o}})}zt.prototype=tn.prototype={constructor:zt,on:function(e,t){var n=this._,o=$a(e+"",n),r,i=-1,s=o.length;if(arguments.length<2){for(;++i0)for(var n=new Array(r),o=0,r,i;o=0&&(t=e.slice(0,n))!=="xmlns"&&(e=e.slice(n+1)),Ao.hasOwnProperty(t)?{space:Ao[t],local:e}:e}function Ha(e){return function(){var t=this.ownerDocument,n=this.namespaceURI;return n===Pn&&t.documentElement.namespaceURI===Pn?t.createElement(e):t.createElementNS(n,e)}}function za(e){return function(){return this.ownerDocument.createElementNS(e.space,e.local)}}function zr(e){var t=nn(e);return(t.local?za:Ha)(t)}function Oa(){}function Wn(e){return e==null?Oa:function(){return this.querySelector(e)}}function La(e){typeof e!="function"&&(e=Wn(e));for(var t=this._groups,n=t.length,o=new Array(n),r=0;r=p&&(p=C+1);!(A=w[p])&&++p=0;)(s=o[r])&&(i&&s.compareDocumentPosition(i)^4&&i.parentNode.insertBefore(s,i),i=s);return this}function lc(e){e||(e=fc);function t(f,d){return f&&d?e(f.__data__,d.__data__):!f-!d}for(var n=this._groups,o=n.length,r=new Array(o),i=0;it?1:e>=t?0:NaN}function dc(){var e=arguments[0];return arguments[0]=this,e.apply(null,arguments),this}function hc(){return Array.from(this)}function gc(){for(var e=this._groups,t=0,n=e.length;t1?this.each((t==null?Cc:typeof t=="function"?Mc:Nc)(e,t,n??"")):Je(this.node(),e)}function Je(e,t){return e.style.getPropertyValue(t)||jr(e).getComputedStyle(e,null).getPropertyValue(t)}function Ic(e){return function(){delete this[e]}}function Tc(e,t){return function(){this[e]=t}}function kc(e,t){return function(){var n=t.apply(this,arguments);n==null?delete this[e]:this[e]=n}}function Rc(e,t){return arguments.length>1?this.each((t==null?Ic:typeof t=="function"?kc:Tc)(e,t)):this.node()[e]}function Fr(e){return e.trim().split(/^|\s+/)}function qn(e){return e.classList||new Yr(e)}function Yr(e){this._node=e,this._names=Fr(e.getAttribute("class")||"")}Yr.prototype={add:function(e){var t=this._names.indexOf(e);t<0&&(this._names.push(e),this._node.setAttribute("class",this._names.join(" ")))},remove:function(e){var t=this._names.indexOf(e);t>=0&&(this._names.splice(t,1),this._node.setAttribute("class",this._names.join(" ")))},contains:function(e){return this._names.indexOf(e)>=0}};function Xr(e,t){for(var n=qn(e),o=-1,r=t.length;++o=0&&(n=t.slice(o+1),t=t.slice(0,o)),{type:t,name:n}})}function su(e){return function(){var t=this.__on;if(t){for(var n=0,o=-1,r=t.length,i;n()=>e;function $n(e,{sourceEvent:t,subject:n,target:o,identifier:r,active:i,x:s,y:a,dx:u,dy:c,dispatch:l}){Object.defineProperties(this,{type:{value:e,enumerable:!0,configurable:!0},sourceEvent:{value:t,enumerable:!0,configurable:!0},subject:{value:n,enumerable:!0,configurable:!0},target:{value:o,enumerable:!0,configurable:!0},identifier:{value:r,enumerable:!0,configurable:!0},active:{value:i,enumerable:!0,configurable:!0},x:{value:s,enumerable:!0,configurable:!0},y:{value:a,enumerable:!0,configurable:!0},dx:{value:u,enumerable:!0,configurable:!0},dy:{value:c,enumerable:!0,configurable:!0},_:{value:l}})}$n.prototype.on=function(){var e=this._.on.apply(this._,arguments);return e===this._?this:e};function mu(e){return!e.ctrlKey&&!e.button}function yu(){return this.parentNode}function xu(e,t){return t??{x:e.x,y:e.y}}function wu(){return navigator.maxTouchPoints||"ontouchstart"in this}function Kr(){var e=mu,t=yu,n=xu,o=wu,r={},i=tn("start","drag","end"),s=0,a,u,c,l,f=0;function d(v){v.on("mousedown.drag",h).filter(o).on("touchstart.drag",w).on("touchmove.drag",y,pu).on("touchend.drag touchcancel.drag",C).style("touch-action","none").style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}function h(v,A){if(!(l||!e.call(this,v,A))){var S=p(this,t.call(this,v,A),v,A,"mouse");S&&(le(v.view).on("mousemove.drag",g,ht).on("mouseup.drag",_,ht),Gr(v.view),vn(v),c=!1,a=v.clientX,u=v.clientY,S("start",v))}}function g(v){if(Ke(v),!c){var A=v.clientX-a,S=v.clientY-u;c=A*A+S*S>f}r.mouse("drag",v)}function _(v){le(v.view).on("mousemove.drag mouseup.drag",null),Ur(v.view,c),Ke(v),r.mouse("end",v)}function w(v,A){if(e.call(this,v,A)){var S=v.changedTouches,b=t.call(this,v,A),T=S.length,k,F;for(k=0;k>8&15|t>>4&240,t>>4&15|t&240,(t&15)<<4|t&15,1):n===8?It(t>>24&255,t>>16&255,t>>8&255,(t&255)/255):n===4?It(t>>12&15|t>>8&240,t>>8&15|t>>4&240,t>>4&15|t&240,((t&15)<<4|t&15)/255):null):(t=_u.exec(e))?new ue(t[1],t[2],t[3],1):(t=Eu.exec(e))?new ue(t[1]*255/100,t[2]*255/100,t[3]*255/100,1):(t=bu.exec(e))?It(t[1],t[2],t[3],t[4]):(t=Su.exec(e))?It(t[1]*255/100,t[2]*255/100,t[3]*255/100,t[4]):(t=Cu.exec(e))?Do(t[1],t[2]/100,t[3]/100,1):(t=Nu.exec(e))?Do(t[1],t[2]/100,t[3]/100,t[4]):Io.hasOwnProperty(e)?Ro(Io[e]):e==="transparent"?new ue(NaN,NaN,NaN,0):null}function Ro(e){return new ue(e>>16&255,e>>8&255,e&255,1)}function It(e,t,n,o){return o<=0&&(e=t=n=NaN),new ue(e,t,n,o)}function Iu(e){return e instanceof bt||(e=Fe(e)),e?(e=e.rgb(),new ue(e.r,e.g,e.b,e.opacity)):new ue}function Dn(e,t,n,o){return arguments.length===1?Iu(e):new ue(e,t,n,o??1)}function ue(e,t,n,o){this.r=+e,this.g=+t,this.b=+n,this.opacity=+o}Gn(ue,Dn,Qr(bt,{brighter(e){return e=e==null?Ft:Math.pow(Ft,e),new ue(this.r*e,this.g*e,this.b*e,this.opacity)},darker(e){return e=e==null?gt:Math.pow(gt,e),new ue(this.r*e,this.g*e,this.b*e,this.opacity)},rgb(){return this},clamp(){return new ue(Be(this.r),Be(this.g),Be(this.b),Yt(this.opacity))},displayable(){return-.5<=this.r&&this.r<255.5&&-.5<=this.g&&this.g<255.5&&-.5<=this.b&&this.b<255.5&&0<=this.opacity&&this.opacity<=1},hex:Po,formatHex:Po,formatHex8:Tu,formatRgb:$o,toString:$o}));function Po(){return`#${Ve(this.r)}${Ve(this.g)}${Ve(this.b)}`}function Tu(){return`#${Ve(this.r)}${Ve(this.g)}${Ve(this.b)}${Ve((isNaN(this.opacity)?1:this.opacity)*255)}`}function $o(){const e=Yt(this.opacity);return`${e===1?"rgb(":"rgba("}${Be(this.r)}, ${Be(this.g)}, ${Be(this.b)}${e===1?")":`, ${e})`}`}function Yt(e){return isNaN(e)?1:Math.max(0,Math.min(1,e))}function Be(e){return Math.max(0,Math.min(255,Math.round(e)||0))}function Ve(e){return e=Be(e),(e<16?"0":"")+e.toString(16)}function Do(e,t,n,o){return o<=0?e=t=n=NaN:n<=0||n>=1?e=t=NaN:t<=0&&(e=NaN),new ge(e,t,n,o)}function Jr(e){if(e instanceof ge)return new ge(e.h,e.s,e.l,e.opacity);if(e instanceof bt||(e=Fe(e)),!e)return new ge;if(e instanceof ge)return e;e=e.rgb();var t=e.r/255,n=e.g/255,o=e.b/255,r=Math.min(t,n,o),i=Math.max(t,n,o),s=NaN,a=i-r,u=(i+r)/2;return a?(t===i?s=(n-o)/a+(n0&&u<1?0:s,new ge(s,a,u,e.opacity)}function ku(e,t,n,o){return arguments.length===1?Jr(e):new ge(e,t,n,o??1)}function ge(e,t,n,o){this.h=+e,this.s=+t,this.l=+n,this.opacity=+o}Gn(ge,ku,Qr(bt,{brighter(e){return e=e==null?Ft:Math.pow(Ft,e),new ge(this.h,this.s,this.l*e,this.opacity)},darker(e){return e=e==null?gt:Math.pow(gt,e),new ge(this.h,this.s,this.l*e,this.opacity)},rgb(){var e=this.h%360+(this.h<0)*360,t=isNaN(e)||isNaN(this.s)?0:this.s,n=this.l,o=n+(n<.5?n:1-n)*t,r=2*n-o;return new ue(_n(e>=240?e-240:e+120,r,o),_n(e,r,o),_n(e<120?e+240:e-120,r,o),this.opacity)},clamp(){return new ge(Ho(this.h),Tt(this.s),Tt(this.l),Yt(this.opacity))},displayable(){return(0<=this.s&&this.s<=1||isNaN(this.s))&&0<=this.l&&this.l<=1&&0<=this.opacity&&this.opacity<=1},formatHsl(){const e=Yt(this.opacity);return`${e===1?"hsl(":"hsla("}${Ho(this.h)}, ${Tt(this.s)*100}%, ${Tt(this.l)*100}%${e===1?")":`, ${e})`}`}}));function Ho(e){return e=(e||0)%360,e<0?e+360:e}function Tt(e){return Math.max(0,Math.min(1,e||0))}function _n(e,t,n){return(e<60?t+(n-t)*e/60:e<180?n:e<240?t+(n-t)*(240-e)/60:t)*255}const Un=e=>()=>e;function Ru(e,t){return function(n){return e+n*t}}function Pu(e,t,n){return e=Math.pow(e,n),t=Math.pow(t,n)-e,n=1/n,function(o){return Math.pow(e+o*t,n)}}function $u(e){return(e=+e)==1?ei:function(t,n){return n-t?Pu(t,n,e):Un(isNaN(t)?n:t)}}function ei(e,t){var n=t-e;return n?Ru(e,n):Un(isNaN(e)?t:e)}const Xt=(function e(t){var n=$u(t);function o(r,i){var s=n((r=Dn(r)).r,(i=Dn(i)).r),a=n(r.g,i.g),u=n(r.b,i.b),c=ei(r.opacity,i.opacity);return function(l){return r.r=s(l),r.g=a(l),r.b=u(l),r.opacity=c(l),r+""}}return o.gamma=e,o})(1);function Du(e,t){t||(t=[]);var n=e?Math.min(t.length,e.length):0,o=t.slice(),r;return function(i){for(r=0;rn&&(i=t.slice(n,i),a[s]?a[s]+=i:a[++s]=i),(o=o[0])===(r=r[0])?a[s]?a[s]+=r:a[++s]=r:(a[++s]=null,u.push({i:s,x:_e(o,r)})),n=En.lastIndex;return n180?l+=360:l-c>180&&(c+=360),d.push({i:f.push(r(f)+"rotate(",null,o)-2,x:_e(c,l)})):l&&f.push(r(f)+"rotate("+l+o)}function a(c,l,f,d){c!==l?d.push({i:f.push(r(f)+"skewX(",null,o)-2,x:_e(c,l)}):l&&f.push(r(f)+"skewX("+l+o)}function u(c,l,f,d,h,g){if(c!==f||l!==d){var _=h.push(r(h)+"scale(",null,",",null,")");g.push({i:_-4,x:_e(c,f)},{i:_-2,x:_e(l,d)})}else(f!==1||d!==1)&&h.push(r(h)+"scale("+f+","+d+")")}return function(c,l){var f=[],d=[];return c=e(c),l=e(l),i(c.translateX,c.translateY,l.translateX,l.translateY,f,d),s(c.rotate,l.rotate,f,d),a(c.skewX,l.skewX,f,d),u(c.scaleX,c.scaleY,l.scaleX,l.scaleY,f,d),c=l=null,function(h){for(var g=-1,_=d.length,w;++g<_;)f[(w=d[g]).i]=w.x(h);return f.join("")}}}var Yu=oi(ju,"px, ","px)","deg)"),Xu=oi(Fu,", ",")",")"),Zu=1e-12;function Oo(e){return((e=Math.exp(e))+1/e)/2}function Wu(e){return((e=Math.exp(e))-1/e)/2}function qu(e){return((e=Math.exp(2*e))-1)/(e+1)}const Ot=(function e(t,n,o){function r(i,s){var a=i[0],u=i[1],c=i[2],l=s[0],f=s[1],d=s[2],h=l-a,g=f-u,_=h*h+g*g,w,y;if(_=0&&e._call.call(void 0,t),e=e._next;--et}function Lo(){Ye=(Wt=mt.now())+on,et=ut=0;try{Uu()}finally{et=0,Qu(),Ye=0}}function Ku(){var e=mt.now(),t=e-Wt;t>ri&&(on-=t,Wt=e)}function Qu(){for(var e,t=Zt,n,o=1/0;t;)t._call?(o>t._time&&(o=t._time),e=t,t=t._next):(n=t._next,t._next=null,t=e?e._next=n:Zt=n);lt=e,On(o)}function On(e){if(!et){ut&&(ut=clearTimeout(ut));var t=e-Ye;t>24?(e<1/0&&(ut=setTimeout(Lo,e-mt.now()-on)),at&&(at=clearInterval(at))):(at||(Wt=mt.now(),at=setInterval(Ku,ri)),et=1,ii(Lo))}}function Vo(e,t,n){var o=new qt;return t=t==null?0:+t,o.restart(r=>{o.stop(),e(r+t)},t,n),o}var Ju=tn("start","end","cancel","interrupt"),el=[],ai=0,Bo=1,Ln=2,Lt=3,jo=4,Vn=5,Vt=6;function rn(e,t,n,o,r,i){var s=e.__transition;if(!s)e.__transition={};else if(n in s)return;tl(e,n,{name:t,index:o,group:r,on:Ju,tween:el,time:i.time,delay:i.delay,duration:i.duration,ease:i.ease,timer:null,state:ai})}function Qn(e,t){var n=xe(e,t);if(n.state>ai)throw new Error("too late; already scheduled");return n}function be(e,t){var n=xe(e,t);if(n.state>Lt)throw new Error("too late; already running");return n}function xe(e,t){var n=e.__transition;if(!n||!(n=n[t]))throw new Error("transition not found");return n}function tl(e,t,n){var o=e.__transition,r;o[t]=n,n.timer=si(i,0,n.time);function i(c){n.state=Bo,n.timer.restart(s,n.delay,n.time),n.delay<=c&&s(c-n.delay)}function s(c){var l,f,d,h;if(n.state!==Bo)return u();for(l in o)if(h=o[l],h.name===n.name){if(h.state===Lt)return Vo(s);h.state===jo?(h.state=Vt,h.timer.stop(),h.on.call("interrupt",e,e.__data__,h.index,h.group),delete o[l]):+lLn&&o.state=0&&(t=t.slice(0,n)),!t||t==="start"})}function kl(e,t,n){var o,r,i=Tl(t)?Qn:be;return function(){var s=i(this,e),a=s.on;a!==o&&(r=(o=a).copy()).on(t,n),s.on=r}}function Rl(e,t){var n=this._id;return arguments.length<2?xe(this.node(),n).on.on(e):this.each(kl(n,e,t))}function Pl(e){return function(){var t=this.parentNode;for(var n in this.__transition)if(+n!==e)return;t&&t.removeChild(this)}}function $l(){return this.on("end.remove",Pl(this._id))}function Dl(e){var t=this._name,n=this._id;typeof e!="function"&&(e=Wn(e));for(var o=this._groups,r=o.length,i=new Array(r),s=0;s()=>e;function af(e,{sourceEvent:t,target:n,transform:o,dispatch:r}){Object.defineProperties(this,{type:{value:e,enumerable:!0,configurable:!0},sourceEvent:{value:t,enumerable:!0,configurable:!0},target:{value:n,enumerable:!0,configurable:!0},transform:{value:o,enumerable:!0,configurable:!0},_:{value:r}})}function Te(e,t,n){this.k=e,this.x=t,this.y=n}Te.prototype={constructor:Te,scale:function(e){return e===1?this:new Te(this.k*e,this.x,this.y)},translate:function(e,t){return e===0&t===0?this:new Te(this.k,this.x+this.k*e,this.y+this.k*t)},apply:function(e){return[e[0]*this.k+this.x,e[1]*this.k+this.y]},applyX:function(e){return e*this.k+this.x},applyY:function(e){return e*this.k+this.y},invert:function(e){return[(e[0]-this.x)/this.k,(e[1]-this.y)/this.k]},invertX:function(e){return(e-this.x)/this.k},invertY:function(e){return(e-this.y)/this.k},rescaleX:function(e){return e.copy().domain(e.range().map(this.invertX,this).map(e.invert,e))},rescaleY:function(e){return e.copy().domain(e.range().map(this.invertY,this).map(e.invert,e))},toString:function(){return"translate("+this.x+","+this.y+") scale("+this.k+")"}};var sn=new Te(1,0,0);fi.prototype=Te.prototype;function fi(e){for(;!e.__zoom;)if(!(e=e.parentNode))return sn;return e.__zoom}function bn(e){e.stopImmediatePropagation()}function ct(e){e.preventDefault(),e.stopImmediatePropagation()}function cf(e){return(!e.ctrlKey||e.type==="wheel")&&!e.button}function uf(){var e=this;return e instanceof SVGElement?(e=e.ownerSVGElement||e,e.hasAttribute("viewBox")?(e=e.viewBox.baseVal,[[e.x,e.y],[e.x+e.width,e.y+e.height]]):[[0,0],[e.width.baseVal.value,e.height.baseVal.value]]):[[0,0],[e.clientWidth,e.clientHeight]]}function Fo(){return this.__zoom||sn}function lf(e){return-e.deltaY*(e.deltaMode===1?.05:e.deltaMode?1:.002)*(e.ctrlKey?10:1)}function ff(){return navigator.maxTouchPoints||"ontouchstart"in this}function df(e,t,n){var o=e.invertX(t[0][0])-n[0][0],r=e.invertX(t[1][0])-n[1][0],i=e.invertY(t[0][1])-n[0][1],s=e.invertY(t[1][1])-n[1][1];return e.translate(r>o?(o+r)/2:Math.min(0,o)||Math.max(0,r),s>i?(i+s)/2:Math.min(0,i)||Math.max(0,s))}function di(){var e=cf,t=uf,n=df,o=lf,r=ff,i=[0,1/0],s=[[-1/0,-1/0],[1/0,1/0]],a=250,u=Ot,c=tn("start","zoom","end"),l,f,d,h=500,g=150,_=0,w=10;function y(x){x.property("__zoom",Fo).on("wheel.zoom",T,{passive:!1}).on("mousedown.zoom",k).on("dblclick.zoom",F).filter(r).on("touchstart.zoom",z).on("touchmove.zoom",B).on("touchend.zoom touchcancel.zoom",O).style("-webkit-tap-highlight-color","rgba(0,0,0,0)")}y.transform=function(x,M,N,I){var $=x.selection?x.selection():x;$.property("__zoom",Fo),x!==$?A(x,M,N,I):$.interrupt().each(function(){S(this,arguments).event(I).start().zoom(null,typeof M=="function"?M.apply(this,arguments):M).end()})},y.scaleBy=function(x,M,N,I){y.scaleTo(x,function(){var $=this.__zoom.k,P=typeof M=="function"?M.apply(this,arguments):M;return $*P},N,I)},y.scaleTo=function(x,M,N,I){y.transform(x,function(){var $=t.apply(this,arguments),P=this.__zoom,j=N==null?v($):typeof N=="function"?N.apply(this,arguments):N,m=P.invert(j),E=typeof M=="function"?M.apply(this,arguments):M;return n(p(C(P,E),j,m),$,s)},N,I)},y.translateBy=function(x,M,N,I){y.transform(x,function(){return n(this.__zoom.translate(typeof M=="function"?M.apply(this,arguments):M,typeof N=="function"?N.apply(this,arguments):N),t.apply(this,arguments),s)},null,I)},y.translateTo=function(x,M,N,I,$){y.transform(x,function(){var P=t.apply(this,arguments),j=this.__zoom,m=I==null?v(P):typeof I=="function"?I.apply(this,arguments):I;return n(sn.translate(m[0],m[1]).scale(j.k).translate(typeof M=="function"?-M.apply(this,arguments):-M,typeof N=="function"?-N.apply(this,arguments):-N),P,s)},I,$)};function C(x,M){return M=Math.max(i[0],Math.min(i[1],M)),M===x.k?x:new Te(M,x.x,x.y)}function p(x,M,N){var I=M[0]-N[0]*x.k,$=M[1]-N[1]*x.k;return I===x.x&&$===x.y?x:new Te(x.k,I,$)}function v(x){return[(+x[0][0]+ +x[1][0])/2,(+x[0][1]+ +x[1][1])/2]}function A(x,M,N,I){x.on("start.zoom",function(){S(this,arguments).event(I).start()}).on("interrupt.zoom end.zoom",function(){S(this,arguments).event(I).end()}).tween("zoom",function(){var $=this,P=arguments,j=S($,P).event(I),m=t.apply($,P),E=N==null?v(m):typeof N=="function"?N.apply($,P):N,V=Math.max(m[1][0]-m[0][0],m[1][1]-m[0][1]),L=$.__zoom,Y=typeof M=="function"?M.apply($,P):M,W=u(L.invert(E).concat(V/L.k),Y.invert(E).concat(V/Y.k));return function(Z){if(Z===1)Z=Y;else{var H=W(Z),X=V/H[2];Z=new Te(X,E[0]-H[0]*X,E[1]-H[1]*X)}j.zoom(null,Z)}})}function S(x,M,N){return!N&&x.__zooming||new b(x,M)}function b(x,M){this.that=x,this.args=M,this.active=0,this.sourceEvent=null,this.extent=t.apply(x,M),this.taps=0}b.prototype={event:function(x){return x&&(this.sourceEvent=x),this},start:function(){return++this.active===1&&(this.that.__zooming=this,this.emit("start")),this},zoom:function(x,M){return this.mouse&&x!=="mouse"&&(this.mouse[1]=M.invert(this.mouse[0])),this.touch0&&x!=="touch"&&(this.touch0[1]=M.invert(this.touch0[0])),this.touch1&&x!=="touch"&&(this.touch1[1]=M.invert(this.touch1[0])),this.that.__zoom=M,this.emit("zoom"),this},end:function(){return--this.active===0&&(delete this.that.__zooming,this.emit("end")),this},emit:function(x){var M=le(this.that).datum();c.call(x,this.that,new af(x,{sourceEvent:this.sourceEvent,target:y,transform:this.that.__zoom,dispatch:c}),M)}};function T(x,...M){if(!e.apply(this,arguments))return;var N=S(this,M).event(x),I=this.__zoom,$=Math.max(i[0],Math.min(i[1],I.k*Math.pow(2,o.apply(this,arguments)))),P=he(x);if(N.wheel)(N.mouse[0][0]!==P[0]||N.mouse[0][1]!==P[1])&&(N.mouse[1]=I.invert(N.mouse[0]=P)),clearTimeout(N.wheel);else{if(I.k===$)return;N.mouse=[P,I.invert(P)],Bt(this),N.start()}ct(x),N.wheel=setTimeout(j,g),N.zoom("mouse",n(p(C(I,$),N.mouse[0],N.mouse[1]),N.extent,s));function j(){N.wheel=null,N.end()}}function k(x,...M){if(d||!e.apply(this,arguments))return;var N=x.currentTarget,I=S(this,M,!0).event(x),$=le(x.view).on("mousemove.zoom",E,!0).on("mouseup.zoom",V,!0),P=he(x,N),j=x.clientX,m=x.clientY;Gr(x.view),bn(x),I.mouse=[P,this.__zoom.invert(P)],Bt(this),I.start();function E(L){if(ct(L),!I.moved){var Y=L.clientX-j,W=L.clientY-m;I.moved=Y*Y+W*W>_}I.event(L).zoom("mouse",n(p(I.that.__zoom,I.mouse[0]=he(L,N),I.mouse[1]),I.extent,s))}function V(L){$.on("mousemove.zoom mouseup.zoom",null),Ur(L.view,I.moved),ct(L),I.event(L).end()}}function F(x,...M){if(e.apply(this,arguments)){var N=this.__zoom,I=he(x.changedTouches?x.changedTouches[0]:x,this),$=N.invert(I),P=N.k*(x.shiftKey?.5:2),j=n(p(C(N,P),I,$),t.apply(this,M),s);ct(x),a>0?le(this).transition().duration(a).call(A,j,I,x):le(this).call(y.transform,j,I,x)}}function z(x,...M){if(e.apply(this,arguments)){var N=x.touches,I=N.length,$=S(this,M,x.changedTouches.length===I).event(x),P,j,m,E;for(bn(x),j=0;j`Seems like you have not used ${e==="svelte"?"SvelteFlowProvider":"ReactFlowProvider"} as an ancestor. Help: https://${e}flow.dev/error#001`,error002:()=>"It looks like you've created a new nodeTypes or edgeTypes object. If this wasn't on purpose please define the nodeTypes/edgeTypes outside of the component or memoize them.",error003:e=>`Node type "${e}" not found. Using fallback type "default".`,error004:()=>"The parent container needs a width and a height to render the graph.",error005:()=>"Only child nodes can use a parent extent.",error006:()=>"Can't create edge. An edge needs a source and a target.",error007:e=>`The old edge with id=${e} does not exist.`,error009:e=>`Marker type "${e}" doesn't exist.`,error008:(e,{id:t,sourceHandle:n,targetHandle:o})=>`Couldn't create edge for ${e} handle id: "${e==="source"?n:o}", edge id: ${t}.`,error010:()=>"Handle: No node id found. Make sure to only use a Handle inside a custom Node.",error011:e=>`Edge type "${e}" not found. Using fallback type "default".`,error012:e=>`Node with id "${e}" does not exist, it may have been removed. This can happen when a node is deleted before the "onNodeClick" handler is called.`,error013:(e="react")=>`It seems that you haven't loaded the styles. Please import '@xyflow/${e}/dist/style.css' or base.css to make sure everything is working properly.`,error014:()=>"useNodeConnections: No node ID found. Call useNodeConnections inside a custom Node or provide a node ID.",error015:()=>"It seems that you are trying to drag a node that is not initialized. Please use onNodesChange as explained in the docs.",error016:e=>`Edge with id "${e}" does not exist, it may have been removed. This can happen when an edge is deleted before the "onEdgeClick" handler is called.`},yt=[[Number.NEGATIVE_INFINITY,Number.NEGATIVE_INFINITY],[Number.POSITIVE_INFINITY,Number.POSITIVE_INFINITY]],hi=["Enter"," ","Escape"],gi={"node.a11yDescription.default":"Press enter or space to select a node. Press delete to remove it and escape to cancel.","node.a11yDescription.keyboardDisabled":"Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.","node.a11yDescription.ariaLiveMessage":({direction:e,x:t,y:n})=>`Moved selected node ${e}. New position, x: ${t}, y: ${n}`,"edge.a11yDescription.default":"Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.","controls.ariaLabel":"Control Panel","controls.zoomIn.ariaLabel":"Zoom In","controls.zoomOut.ariaLabel":"Zoom Out","controls.fitView.ariaLabel":"Fit View","controls.interactive.ariaLabel":"Toggle Interactivity","minimap.ariaLabel":"Mini Map","handle.ariaLabel":"Handle"};var tt;(function(e){e.Strict="strict",e.Loose="loose"})(tt||(tt={}));var je;(function(e){e.Free="free",e.Vertical="vertical",e.Horizontal="horizontal"})(je||(je={}));var xt;(function(e){e.Partial="partial",e.Full="full"})(xt||(xt={}));const pi={inProgress:!1,isValid:null,from:null,fromHandle:null,fromPosition:null,fromNode:null,to:null,toHandle:null,toPosition:null,toNode:null,pointer:null};var $e;(function(e){e.Bezier="default",e.Straight="straight",e.Step="step",e.SmoothStep="smoothstep",e.SimpleBezier="simplebezier"})($e||($e={}));var Gt;(function(e){e.Arrow="arrow",e.ArrowClosed="arrowclosed"})(Gt||(Gt={}));var G;(function(e){e.Left="left",e.Top="top",e.Right="right",e.Bottom="bottom"})(G||(G={}));const Yo={[G.Left]:G.Right,[G.Right]:G.Left,[G.Top]:G.Bottom,[G.Bottom]:G.Top};function mi(e){return e===null?null:e?"valid":"invalid"}const yi=e=>!!e&&typeof e=="object"&&"id"in e&&"source"in e&&"target"in e,hf=e=>!!e&&typeof e=="object"&&"id"in e&&"position"in e&&!("source"in e)&&!("target"in e),eo=e=>!!e&&typeof e=="object"&&"id"in e&&"internals"in e&&!("source"in e)&&!("target"in e),St=(e,t=[0,0])=>{const{width:n,height:o}=Se(e),r=e.origin??t,i=n*r[0],s=o*r[1];return{x:e.position.x-i,y:e.position.y-s}},gf=(e,t={nodeOrigin:[0,0]})=>{if(e.length===0)return{x:0,y:0,width:0,height:0};const n=e.reduce((o,r)=>{const i=typeof r=="string";let s=!t.nodeLookup&&!i?r:void 0;t.nodeLookup&&(s=i?t.nodeLookup.get(r):eo(r)?r:t.nodeLookup.get(r.id));const a=s?Ut(s,t.nodeOrigin):{x:0,y:0,x2:0,y2:0};return an(o,a)},{x:1/0,y:1/0,x2:-1/0,y2:-1/0});return cn(n)},Ct=(e,t={})=>{let n={x:1/0,y:1/0,x2:-1/0,y2:-1/0},o=!1;return e.forEach(r=>{(t.filter===void 0||t.filter(r))&&(n=an(n,Ut(r)),o=!0)}),o?cn(n):{x:0,y:0,width:0,height:0}},to=(e,t,[n,o,r]=[0,0,1],i=!1,s=!1)=>{const a=(t.x-n)/r,u=(t.y-o)/r,c=t.width/r,l=t.height/r,f=[];for(const d of e.values()){const{measured:h,selectable:g=!0,hidden:_=!1}=d;if(s&&!g||_)continue;const w=h.width??d.width??d.initialWidth??0,y=h.height??d.height??d.initialHeight??0,{x:C,y:p}=d.internals.positionAbsolute,v=_i(a,u,c,l,C,p,w,y),A=w*y,S=i&&v>0;(!d.internals.handleBounds||S||v>=A||d.dragging)&&f.push(d)}return f},pf=(e,t)=>{const n=new Set;return e.forEach(o=>{n.add(o.id)}),t.filter(o=>n.has(o.source)||n.has(o.target))};function mf(e,t){const n=new Map,o=t?.nodes?new Set(t.nodes.map(r=>r.id)):null;return e.forEach(r=>{let i;if(t?.includeHiddenNodes){const{width:s,height:a}=Se(r);i=s>0&&a>0}else i=!!(r.measured.width&&r.measured.height&&!r.hidden);i&&(!o||o.has(r.id))&&n.set(r.id,r)}),n}async function yf({nodes:e,width:t,height:n,panZoom:o,minZoom:r,maxZoom:i},s){if(e.size===0)return!0;const a=mf(e,s),u=Ct(a),c=oo(u,t,n,s?.minZoom??r,s?.maxZoom??i,s?.padding??.1);return await o.setViewport(c,{duration:s?.duration,ease:s?.ease,interpolate:s?.interpolate}),!0}function xi({nodeId:e,nextPosition:t,nodeLookup:n,nodeOrigin:o=[0,0],nodeExtent:r,onError:i}){const s=n.get(e),a=s.parentId?n.get(s.parentId):void 0,{x:u,y:c}=a?a.internals.positionAbsolute:{x:0,y:0},l=s.origin??o;let f=s.extent||r;if(s.extent==="parent"&&!s.expandParent)if(!a)i?.("005",ye.error005());else{const h=a.measured.width,g=a.measured.height;h&&g&&(f=[[u,c],[u+h,c+g]])}else a&&Ze(s.extent)&&(f=[[s.extent[0][0]+u,s.extent[0][1]+c],[s.extent[1][0]+u,s.extent[1][1]+c]]);const d=Ze(f)?Xe(t,f,s.measured):t;return(s.measured.width===void 0||s.measured.height===void 0)&&i?.("015",ye.error015()),{position:{x:d.x-u+(s.measured.width??0)*l[0],y:d.y-c+(s.measured.height??0)*l[1]},positionAbsolute:d}}async function xf({nodesToRemove:e=[],edgesToRemove:t=[],nodes:n,edges:o,onBeforeDelete:r}){const i=new Set(e.map(d=>d.id)),s=[];for(const d of n){if(d.deletable===!1)continue;const h=i.has(d.id),g=!h&&d.parentId&&s.find(_=>_.id===d.parentId);(h||g)&&s.push(d)}const a=new Set(t.map(d=>d.id)),u=o.filter(d=>d.deletable!==!1),l=pf(s,u);for(const d of u)a.has(d.id)&&!l.find(g=>g.id===d.id)&&l.push(d);if(!r)return{edges:l,nodes:s};const f=await r({nodes:s,edges:l});return typeof f=="boolean"?f?{edges:l,nodes:s}:{edges:[],nodes:[]}:f}const nt=(e,t=0,n=1)=>Math.min(Math.max(e,t),n),Xe=(e={x:0,y:0},t,n)=>({x:nt(e.x,t[0][0],t[1][0]-(n?.width??0)),y:nt(e.y,t[0][1],t[1][1]-(n?.height??0))});function wi(e,t,n){const{width:o,height:r}=Se(n),{x:i,y:s}=n.internals.positionAbsolute;return Xe(e,[[i,s],[i+o,s+r]],t)}const Xo=(e,t,n)=>en?-nt(Math.abs(e-n),1,t)/t:0,no=(e,t,n=15,o=40)=>{const r=Xo(e.x,o,t.width-o)*n,i=Xo(e.y,o,t.height-o)*n;return[r,i]},an=(e,t)=>({x:Math.min(e.x,t.x),y:Math.min(e.y,t.y),x2:Math.max(e.x2,t.x2),y2:Math.max(e.y2,t.y2)}),Bn=({x:e,y:t,width:n,height:o})=>({x:e,y:t,x2:e+n,y2:t+o}),cn=({x:e,y:t,x2:n,y2:o})=>({x:e,y:t,width:n-e,height:o-t}),wt=(e,t=[0,0])=>{const{x:n,y:o}=eo(e)?e.internals.positionAbsolute:St(e,t);return{x:n,y:o,width:e.measured?.width??e.width??e.initialWidth??0,height:e.measured?.height??e.height??e.initialHeight??0}},Ut=(e,t=[0,0])=>{const{x:n,y:o}=eo(e)?e.internals.positionAbsolute:St(e,t);return{x:n,y:o,x2:n+(e.measured?.width??e.width??e.initialWidth??0),y2:o+(e.measured?.height??e.height??e.initialHeight??0)}},vi=(e,t)=>cn(an(Bn(e),Bn(t))),_i=(e,t,n,o,r,i,s,a)=>{const u=Math.max(0,Math.min(e+n,r+s)-Math.max(e,r)),c=Math.max(0,Math.min(t+o,i+a)-Math.max(t,i));return Math.ceil(u*c)},Kt=(e,t)=>_i(e.x,e.y,e.width,e.height,t.x,t.y,t.width,t.height),Zo=e=>pe(e.width)&&pe(e.height)&&pe(e.x)&&pe(e.y),pe=e=>!isNaN(e)&&isFinite(e),Ei=(e,t)=>(n,o)=>{},Nt=(e,t=[1,1])=>({x:t[0]*Math.round(e.x/t[0]),y:t[1]*Math.round(e.y/t[1])}),Mt=({x:e,y:t},[n,o,r],i=!1,s=[1,1])=>{const a={x:(e-n)/r,y:(t-o)/r};return i?Nt(a,s):a},ot=({x:e,y:t},[n,o,r])=>({x:e*r+n,y:t*r+o});function qe(e,t){if(typeof e=="number")return Math.floor((t-t/(1+e))*.5);if(typeof e=="string"&&e.endsWith("px")){const n=parseFloat(e);if(!Number.isNaN(n))return Math.floor(n)}if(typeof e=="string"&&e.endsWith("%")){const n=parseFloat(e);if(!Number.isNaN(n))return Math.floor(t*n*.01)}return console.error(`The padding value "${e}" is invalid. Please provide a number or a string with a valid unit (px or %).`),0}function wf(e,t,n){if(typeof e=="string"||typeof e=="number"){const o=qe(e,n),r=qe(e,t);return{top:o,right:r,bottom:o,left:r,x:r*2,y:o*2}}if(typeof e=="object"){const o=qe(e.top??e.y??0,n),r=qe(e.bottom??e.y??0,n),i=qe(e.left??e.x??0,t),s=qe(e.right??e.x??0,t);return{top:o,right:s,bottom:r,left:i,x:i+s,y:o+r}}return{top:0,right:0,bottom:0,left:0,x:0,y:0}}function vf(e,t,n,o,r,i){const{x:s,y:a}=ot(e,[t,n,o]),{x:u,y:c}=ot({x:e.x+e.width,y:e.y+e.height},[t,n,o]),l=r-u,f=i-c;return{left:Math.floor(s),top:Math.floor(a),right:Math.floor(l),bottom:Math.floor(f)}}const oo=(e,t,n,o,r,i)=>{const s=wf(i,t,n),a=(t-s.x)/e.width,u=(n-s.y)/e.height,c=Math.min(a,u),l=nt(c,o,r),f=e.x+e.width/2,d=e.y+e.height/2,h=t/2-f*l,g=n/2-d*l,_=vf(e,h,g,l,t,n),w={left:Math.min(_.left-s.left,0),top:Math.min(_.top-s.top,0),right:Math.min(_.right-s.right,0),bottom:Math.min(_.bottom-s.bottom,0)};return{x:h-w.left+w.right,y:g-w.top+w.bottom,zoom:l}},vt=()=>typeof navigator<"u"&&navigator?.userAgent?.indexOf("Mac")>=0;function Ze(e){return e!=null&&e!=="parent"}function Se(e){return{width:e.measured?.width??e.width??e.initialWidth??0,height:e.measured?.height??e.height??e.initialHeight??0}}function bi(e){return(e.measured?.width??e.width??e.initialWidth)!==void 0&&(e.measured?.height??e.height??e.initialHeight)!==void 0}function Si(e,t={width:0,height:0},n,o,r){const i={...e},s=o.get(n);if(s){const a=s.origin||r;i.x+=s.internals.positionAbsolute.x-(t.width??0)*a[0],i.y+=s.internals.positionAbsolute.y-(t.height??0)*a[1]}return i}function Wo(e,t){if(e.size!==t.size)return!1;for(const n of e)if(!t.has(n))return!1;return!0}function _f(){let e,t;return{promise:new Promise((o,r)=>{e=o,t=r}),resolve:e,reject:t}}function Ef(e){return{...gi,...e||{}}}function dt(e,{snapGrid:t=[0,0],snapToGrid:n=!1,transform:o,containerBounds:r}){const{x:i,y:s}=me(e),a=Mt({x:i-(r?.left??0),y:s-(r?.top??0)},o),{x:u,y:c}=n?Nt(a,t):a;return{xSnapped:u,ySnapped:c,...a}}const ro=e=>({width:e.offsetWidth,height:e.offsetHeight}),Ci=e=>e?.getRootNode?.()||window?.document,bf=["INPUT","SELECT","TEXTAREA"];function Ni(e){const t=e.composedPath?.()?.[0]||e.target;return t?.nodeType!==1?!1:bf.includes(t.nodeName)||t.hasAttribute("contenteditable")||!!t.closest(".nokey")}const Mi=e=>"clientX"in e,me=(e,t)=>{const n=Mi(e),o=n?e.clientX:e.touches?.[0].clientX,r=n?e.clientY:e.touches?.[0].clientY;return{x:o-(t?.left??0),y:r-(t?.top??0)}},qo=(e,t,n,o,r)=>{const i=t.querySelectorAll(`.${e}`);return!i||!i.length?null:Array.from(i).map(s=>{const a=s.getBoundingClientRect();return{id:s.getAttribute("data-handleid"),type:e,nodeId:r,position:s.getAttribute("data-handlepos"),x:(a.left-n.left)/o,y:(a.top-n.top)/o,...ro(s)}})};function Ai({sourceX:e,sourceY:t,targetX:n,targetY:o,sourceControlX:r,sourceControlY:i,targetControlX:s,targetControlY:a}){const u=e*.125+r*.375+s*.375+n*.125,c=t*.125+i*.375+a*.375+o*.125,l=Math.abs(u-e),f=Math.abs(c-t);return[u,c,l,f]}function Pt(e,t){return e>=0?.5*e:t*25*Math.sqrt(-e)}function Go({pos:e,x1:t,y1:n,x2:o,y2:r,c:i}){switch(e){case G.Left:return[t-Pt(t-o,i),n];case G.Right:return[t+Pt(o-t,i),n];case G.Top:return[t,n-Pt(n-r,i)];case G.Bottom:return[t,n+Pt(r-n,i)]}}function Ii({sourceX:e,sourceY:t,sourcePosition:n=G.Bottom,targetX:o,targetY:r,targetPosition:i=G.Top,curvature:s=.25}){const[a,u]=Go({pos:n,x1:e,y1:t,x2:o,y2:r,c:s}),[c,l]=Go({pos:i,x1:o,y1:r,x2:e,y2:t,c:s}),[f,d,h,g]=Ai({sourceX:e,sourceY:t,targetX:o,targetY:r,sourceControlX:a,sourceControlY:u,targetControlX:c,targetControlY:l});return[`M${e},${t} C${a},${u} ${c},${l} ${o},${r}`,f,d,h,g]}function Ti({sourceX:e,sourceY:t,targetX:n,targetY:o}){const r=Math.abs(n-e)/2,i=n0}const Nf=({source:e,sourceHandle:t,target:n,targetHandle:o})=>`xy-edge__${e}${t||""}-${n}${o||""}`,Mf=(e,t)=>t.some(n=>n.source===e.source&&n.target===e.target&&(n.sourceHandle===e.sourceHandle||!n.sourceHandle&&!e.sourceHandle)&&(n.targetHandle===e.targetHandle||!n.targetHandle&&!e.targetHandle)),Af=(e,t,n={})=>{if(!e.source||!e.target)return n.onError?.("006",ye.error006()),t;const o=n.getEdgeId||Nf;let r;return yi(e)?r={...e}:r={...e,id:o(e)},Mf(r,t)?t:(r.sourceHandle===null&&delete r.sourceHandle,r.targetHandle===null&&delete r.targetHandle,t.concat(r))};function ki({sourceX:e,sourceY:t,targetX:n,targetY:o}){const[r,i,s,a]=Ti({sourceX:e,sourceY:t,targetX:n,targetY:o});return[`M ${e},${t}L ${n},${o}`,r,i,s,a]}const Uo={[G.Left]:{x:-1,y:0},[G.Right]:{x:1,y:0},[G.Top]:{x:0,y:-1},[G.Bottom]:{x:0,y:1}},If=({source:e,sourcePosition:t=G.Bottom,target:n})=>t===G.Left||t===G.Right?e.xMath.sqrt(Math.pow(t.x-e.x,2)+Math.pow(t.y-e.y,2));function Tf({source:e,sourcePosition:t=G.Bottom,target:n,targetPosition:o=G.Top,center:r,offset:i,stepPosition:s}){const a=Uo[t],u=Uo[o],c={x:e.x+a.x*i,y:e.y+a.y*i},l={x:n.x+u.x*i,y:n.y+u.y*i},f=If({source:c,sourcePosition:t,target:l}),d=f.x!==0?"x":"y",h=f[d];let g=[],_,w;const y={x:0,y:0},C={x:0,y:0},[,,p,v]=Ti({sourceX:e.x,sourceY:e.y,targetX:n.x,targetY:n.y});if(a[d]*u[d]===-1){d==="x"?(_=r.x??c.x+(l.x-c.x)*s,w=r.y??(c.y+l.y)/2):(_=r.x??(c.x+l.x)/2,w=r.y??c.y+(l.y-c.y)*s);const T=[{x:_,y:c.y},{x:_,y:l.y}],k=[{x:c.x,y:w},{x:l.x,y:w}];a[d]===h?g=d==="x"?T:k:g=d==="x"?k:T}else{const T=[{x:c.x,y:l.y}],k=[{x:l.x,y:c.y}];if(d==="x"?g=a.x===h?k:T:g=a.y===h?T:k,t===o){const x=Math.abs(e[d]-n[d]);if(x<=i){const M=Math.min(i-1,i-x);a[d]===h?y[d]=(c[d]>e[d]?-1:1)*M:C[d]=(l[d]>n[d]?-1:1)*M}}if(t!==o){const x=d==="x"?"y":"x",M=a[d]===u[x],N=c[x]>l[x],I=c[x]=O?(_=(F.x+z.x)/2,w=g[0].y):(_=g[0].x,w=(F.y+z.y)/2)}const A={x:c.x+y.x,y:c.y+y.y},S={x:l.x+C.x,y:l.y+C.y};return[[e,...A.x!==g[0].x||A.y!==g[0].y?[A]:[],...g,...S.x!==g[g.length-1].x||S.y!==g[g.length-1].y?[S]:[],n],_,w,p,v]}function kf(e,t,n,o){const r=Math.min(Ko(e,t)/2,Ko(t,n)/2,o),{x:i,y:s}=t;if(e.x===i&&i===n.x||e.y===s&&s===n.y)return`L${i} ${s}`;if(e.y===s){const c=e.xn.id===t):e[0])||null}function Fn(e,t){return e?typeof e=="string"?e:`${t?`${t}__`:""}${Object.keys(e).sort().map(o=>`${o}=${e[o]}`).join("&")}`:""}function Pf(e,{id:t,defaultColor:n,defaultMarkerStart:o,defaultMarkerEnd:r}){const i=new Set;return e.reduce((s,a)=>([a.markerStart||o,a.markerEnd||r].forEach(u=>{if(u&&typeof u=="object"){const c=Fn(u,t);i.has(c)||(s.push({id:c,color:u.color||n,...u}),i.add(c))}}),s),[]).sort((s,a)=>s.id.localeCompare(a.id))}const Ri=1e3,$f=10,io={nodeOrigin:[0,0],nodeExtent:yt,elevateNodesOnSelect:!0,zIndexMode:"basic",defaults:{}},Df={...io,checkEquality:!0};function so(e,t){const n={...e};for(const o in t)t[o]!==void 0&&(n[o]=t[o]);return n}function Hf(e,t,n){const o=so(io,n);for(const r of e.values())if(r.parentId)co(r,e,t,o);else{const i=St(r,o.nodeOrigin),s=Ze(r.extent)?r.extent:o.nodeExtent,a=Xe(i,s,Se(r));r.internals.positionAbsolute=a}}function zf(e,t){if(!e.handles)return e.measured?t?.internals.handleBounds:void 0;const n=[],o=[];for(const r of e.handles){const i={id:r.id,width:r.width??1,height:r.height??1,nodeId:e.id,x:r.x,y:r.y,position:r.position,type:r.type};r.type==="source"?n.push(i):r.type==="target"&&o.push(i)}return{source:n,target:o}}function ao(e){return e==="manual"}function Yn(e,t,n,o={}){const r=so(Df,o),i={i:0},s=new Map(t),a=r?.elevateNodesOnSelect&&!ao(r.zIndexMode)?Ri:0;let u=e.length>0,c=!1;t.clear(),n.clear();for(const l of e){let f=s.get(l.id);if(r.checkEquality&&l===f?.internals.userNode)t.set(l.id,f);else{const d=St(l,r.nodeOrigin),h=Ze(l.extent)?l.extent:r.nodeExtent,g=Xe(d,h,Se(l));f={...r.defaults,...l,measured:{width:l.measured?.width,height:l.measured?.height},internals:{positionAbsolute:g,handleBounds:zf(l,f),z:Pi(l,a,r.zIndexMode),userNode:l}},t.set(l.id,f)}(f.measured===void 0||f.measured.width===void 0||f.measured.height===void 0)&&!f.hidden&&(u=!1),l.parentId&&co(f,t,n,o,i),c||=l.selected??!1}return{nodesInitialized:u,hasSelectedNodes:c}}function Of(e,t){if(!e.parentId)return;const n=t.get(e.parentId);n?n.set(e.id,e):t.set(e.parentId,new Map([[e.id,e]]))}function co(e,t,n,o,r){const{elevateNodesOnSelect:i,nodeOrigin:s,nodeExtent:a,zIndexMode:u}=so(io,o),c=e.parentId,l=t.get(c);if(!l){console.warn(`Parent node ${c} not found. Please make sure that parent nodes are in front of their child nodes in the nodes array.`);return}Of(e,n),r&&!l.parentId&&l.internals.rootParentIndex===void 0&&u==="auto"&&(l.internals.rootParentIndex=++r.i,l.internals.z=l.internals.z+r.i*$f),r&&l.internals.rootParentIndex!==void 0&&(r.i=l.internals.rootParentIndex);const f=i&&!ao(u)?Ri:0,{x:d,y:h,z:g}=Lf(e,l,s,a,f,u),{positionAbsolute:_}=e.internals,w=d!==_.x||h!==_.y;(w||g!==e.internals.z)&&t.set(e.id,{...e,internals:{...e.internals,positionAbsolute:w?{x:d,y:h}:_,z:g}})}function Pi(e,t,n){const o=pe(e.zIndex)?e.zIndex:0;return ao(n)?o:o+(e.selected?t:0)}function Lf(e,t,n,o,r,i){const{x:s,y:a}=t.internals.positionAbsolute,u=Se(e),c=St(e,n),l=Ze(e.extent)?Xe(c,e.extent,u):c;let f=Xe({x:s+l.x,y:a+l.y},o,u);e.extent==="parent"&&(f=wi(f,u,t));const d=Pi(e,r,i),h=t.internals.z??0;return{x:f.x,y:f.y,z:h>=d?h+1:d}}function uo(e,t,n,o=[0,0]){const r=[],i=new Map;for(const s of e){const a=t.get(s.parentId);if(!a)continue;const u=i.get(s.parentId)?.expandedRect??wt(a),c=vi(u,s.rect);i.set(s.parentId,{expandedRect:c,parent:a})}return i.size>0&&i.forEach(({expandedRect:s,parent:a},u)=>{const c=a.internals.positionAbsolute,l=Se(a),f=a.origin??o,d=s.x0||h>0||w||y)&&(r.push({id:u,type:"position",position:{x:a.position.x-d+w,y:a.position.y-h+y}}),n.get(u)?.forEach(C=>{e.some(p=>p.id===C.id)||r.push({id:C.id,type:"position",position:{x:C.position.x+d,y:C.position.y+h}})})),(l.width0){const h=uo(d,t,n,r);c.push(...h)}return{changes:c,updatedInternals:u}}async function Bf({delta:e,panZoom:t,transform:n,translateExtent:o,width:r,height:i}){if(!t||!e.x&&!e.y)return!1;const s=await t.setViewportConstrained({x:n[0]+e.x,y:n[1]+e.y,zoom:n[2]},[[0,0],[r,i]],o);return!!s&&(s.x!==n[0]||s.y!==n[1]||s.k!==n[2])}function tr(e,t,n,o,r,i){let s=r;const a=o.get(s)||new Map;o.set(s,a.set(n,t)),s=`${r}-${e}`;const u=o.get(s)||new Map;if(o.set(s,u.set(n,t)),i){s=`${r}-${e}-${i}`;const c=o.get(s)||new Map;o.set(s,c.set(n,t))}}function $i(e,t,n){e.clear(),t.clear();for(const o of n){const{source:r,target:i,sourceHandle:s=null,targetHandle:a=null}=o,u={edgeId:o.id,source:r,target:i,sourceHandle:s,targetHandle:a},c=`${r}-${s}--${i}-${a}`,l=`${i}-${a}--${r}-${s}`;tr("source",u,l,e,r,s),tr("target",u,c,e,i,a),t.set(o.id,o)}}function Di(e,t){if(!e.parentId)return!1;const n=t.get(e.parentId);return n?n.selected?!0:Di(n,t):!1}function nr(e,t,n){let o=e;do{if(o?.matches?.(t))return!0;if(o===n)return!1;o=o?.parentElement}while(o);return!1}function jf(e,t,n,o){const r=new Map;for(const[i,s]of e)if((s.selected||s.id===o)&&(!s.parentId||!Di(s,e))&&(s.draggable||t&&typeof s.draggable>"u")){const a=e.get(i);a&&r.set(i,{id:i,position:a.position||{x:0,y:0},distance:{x:n.x-a.internals.positionAbsolute.x,y:n.y-a.internals.positionAbsolute.y},extent:a.extent,parentId:a.parentId,origin:a.origin,expandParent:a.expandParent,internals:{positionAbsolute:a.internals.positionAbsolute||{x:0,y:0}},measured:{width:a.measured.width??0,height:a.measured.height??0}})}return r}function Sn({nodeId:e,dragItems:t,nodeLookup:n,dragging:o=!0}){const r=[];for(const[s,a]of t){const u=n.get(s)?.internals.userNode;u&&r.push({...u,position:a.position,dragging:o})}if(!e)return[r[0],r];const i=n.get(e)?.internals.userNode;return[i?{...i,position:t.get(e)?.position||i.position,dragging:o}:r[0],r]}function Ff({dragItems:e,snapGrid:t,x:n,y:o}){const r=e.values().next().value;if(!r)return null;const i={x:n-r.distance.x,y:o-r.distance.y},s=Nt(i,t);return{x:s.x-i.x,y:s.y-i.y}}function Yf({onNodeMouseDown:e,getStoreItems:t,onDragStart:n,onDrag:o,onDragStop:r}){let i={x:null,y:null},s=0,a=new Map,u=!1,c={x:0,y:0},l=null,f=!1,d=null,h=!1,g=!1,_=null;function w({noDragClassName:C,handleSelector:p,domNode:v,isSelectable:A,nodeId:S,nodeClickDistance:b=0}){d=le(v);function T({x:B,y:O}){const{nodeLookup:x,nodeExtent:M,snapGrid:N,snapToGrid:I,nodeOrigin:$,onNodeDrag:P,onSelectionDrag:j,onError:m,updateNodePositions:E}=t();i={x:B,y:O};let V=!1;const L=a.size>1,Y=L&&M?Bn(Ct(a)):null,W=L&&I?Ff({dragItems:a,snapGrid:N,x:B,y:O}):null;for(const[Z,H]of a){if(!x.has(Z))continue;let X={x:B-H.distance.x,y:O-H.distance.y};I&&(X=W?{x:Math.round(X.x+W.x),y:Math.round(X.y+W.y)}:Nt(X,N));let J=null;if(L&&M&&!H.extent&&Y){const{positionAbsolute:U}=H.internals,ee=U.x-Y.x+M[0][0],ne=U.x+H.measured.width-Y.x2+M[1][0],re=U.y-Y.y+M[0][1],ce=U.y+H.measured.height-Y.y2+M[1][1];J=[[ee,re],[ne,ce]]}const{position:Q,positionAbsolute:q}=xi({nodeId:Z,nextPosition:X,nodeLookup:x,nodeExtent:J||M,nodeOrigin:$,onError:m});V=V||H.position.x!==Q.x||H.position.y!==Q.y,H.position=Q,H.internals.positionAbsolute=q}if(g=g||V,!!V&&(E(a,!0),_&&(o||P||!S&&j))){const[Z,H]=Sn({nodeId:S,dragItems:a,nodeLookup:x});o?.(_,a,Z,H),P?.(_,Z,H),S||j?.(_,H)}}async function k(){if(!l)return;const{transform:B,panBy:O,autoPanSpeed:x,autoPanOnNodeDrag:M}=t();if(!M){u=!1,cancelAnimationFrame(s);return}const[N,I]=no(c,l,x);(N!==0||I!==0)&&(i.x=(i.x??0)-N/B[2],i.y=(i.y??0)-I/B[2],await O({x:N,y:I})&&T(i)),s=requestAnimationFrame(k)}function F(B){const{nodeLookup:O,multiSelectionActive:x,nodesDraggable:M,transform:N,snapGrid:I,snapToGrid:$,selectNodesOnDrag:P,onNodeDragStart:j,onSelectionDragStart:m,unselectNodesAndEdges:E}=t();f=!0,(!P||!A)&&!x&&S&&(O.get(S)?.selected||E()),A&&P&&S&&e?.(S);const V=dt(B.sourceEvent,{transform:N,snapGrid:I,snapToGrid:$,containerBounds:l});if(i=V,a=jf(O,M,V,S),a.size>0&&(n||j||!S&&m)){const[L,Y]=Sn({nodeId:S,dragItems:a,nodeLookup:O});n?.(B.sourceEvent,a,L,Y),j?.(B.sourceEvent,L,Y),S||m?.(B.sourceEvent,Y)}}const z=Kr().clickDistance(b).on("start",B=>{const{domNode:O,nodeDragThreshold:x,transform:M,snapGrid:N,snapToGrid:I}=t();l=O?.getBoundingClientRect()||null,h=!1,g=!1,_=B.sourceEvent,x===0&&F(B),i=dt(B.sourceEvent,{transform:M,snapGrid:N,snapToGrid:I,containerBounds:l}),c=me(B.sourceEvent,l)}).on("drag",B=>{const{autoPanOnNodeDrag:O,transform:x,snapGrid:M,snapToGrid:N,nodeDragThreshold:I,nodeLookup:$}=t(),P=dt(B.sourceEvent,{transform:x,snapGrid:M,snapToGrid:N,containerBounds:l});if(_=B.sourceEvent,(B.sourceEvent.type==="touchmove"&&B.sourceEvent.touches.length>1||S&&!$.has(S))&&(h=!0),!h){if(!u&&O&&f&&(u=!0,k()),!f){const j=me(B.sourceEvent,l),m=j.x-c.x,E=j.y-c.y;Math.sqrt(m*m+E*E)>I&&F(B)}(i.x!==P.xSnapped||i.y!==P.ySnapped)&&a&&f&&(c=me(B.sourceEvent,l),T(P))}}).on("end",B=>{if(!f||h){h&&a.size>0&&t().updateNodePositions(a,!1);return}if(u=!1,f=!1,cancelAnimationFrame(s),a.size>0){const{nodeLookup:O,updateNodePositions:x,onNodeDragStop:M,onSelectionDragStop:N}=t();if(g&&(x(a,!1),g=!1),r||M||!S&&N){const[I,$]=Sn({nodeId:S,dragItems:a,nodeLookup:O,dragging:!1});r?.(B.sourceEvent,a,I,$),M?.(B.sourceEvent,I,$),S||N?.(B.sourceEvent,$)}}}).filter(B=>{const O=B.target;return!B.button&&(!C||!nr(O,`.${C}`,v))&&(!p||nr(O,p,v))});d.call(z)}function y(){d?.on(".drag",null)}return{update:w,destroy:y}}function Xf(e,t,n){const o=[],r={x:e.x-n,y:e.y-n,width:n*2,height:n*2};for(const i of t.values())Kt(r,wt(i))>0&&o.push(i);return o}const Zf=250;function Wf(e,t,n,o){let r=[],i=1/0;const s=Xf(e,n,t+Zf);for(const a of s){const u=[...a.internals.handleBounds?.source??[],...a.internals.handleBounds?.target??[]];for(const c of u){if(o.nodeId===c.nodeId&&o.type===c.type&&o.id===c.id)continue;const{x:l,y:f}=We(a,c,c.position,!0),d=Math.sqrt(Math.pow(l-e.x,2)+Math.pow(f-e.y,2));d>t||(d1){const a=o.type==="source"?"target":"source";return r.find(u=>u.type===a)??r[0]}return r[0]}function Hi(e,t,n,o,r,i=!1){const s=o.get(e);if(!s)return null;const a=r==="strict"?s.internals.handleBounds?.[t]:[...s.internals.handleBounds?.source??[],...s.internals.handleBounds?.target??[]],u=(n?a?.find(c=>c.id===n):a?.[0])??null;return u&&i?{...u,...We(s,u,u.position,!0)}:u}function zi(e,t){return e||(t?.classList.contains("target")?"target":t?.classList.contains("source")?"source":null)}function qf(e,t){let n=null;return t?n=!0:e&&!t&&(n=!1),n}const Oi=()=>!0;function Gf(e,{connectionMode:t,connectionRadius:n,handleId:o,nodeId:r,edgeUpdaterType:i,isTarget:s,domNode:a,nodeLookup:u,lib:c,autoPanOnConnect:l,flowId:f,panBy:d,cancelConnection:h,onConnectStart:g,onConnect:_,onConnectEnd:w,isValidConnection:y=Oi,onReconnectEnd:C,updateConnection:p,getTransform:v,getFromHandle:A,autoPanSpeed:S,dragThreshold:b=1,handleDomNode:T}){const k=Ci(e.target);let F=0,z;const{x:B,y:O}=me(e),x=zi(i,T),M=a?.getBoundingClientRect();let N=!1;if(!M||!x)return;const I=Hi(r,x,o,u,t);if(!I)return;let $=me(e,M),P=!1,j=null,m=!1,E=null;function V(){if(!l||!M)return;const[Q,q]=no($,M,S);d({x:Q,y:q}),F=requestAnimationFrame(V)}const L={...I,nodeId:r,type:x,position:I.position},Y=u.get(r);let Z={inProgress:!0,isValid:null,from:We(Y,L,G.Left,!0),fromHandle:L,fromPosition:L.position,fromNode:Y,to:$,toHandle:null,toPosition:Yo[L.position],toNode:null,pointer:$};function H(){N=!0,p(Z),g?.(e,{nodeId:r,handleId:o,handleType:x})}b===0&&H();function X(Q){if(!N){const{x:ce,y:Ce}=me(Q),we=ce-B,ve=Ce-O;if(!(we*we+ve*ve>b*b))return;H()}if(!A()||!L){J(Q);return}const q=v();$=me(Q,M),z=Wf(Mt($,q,!1,[1,1]),n,u,L),P||(V(),P=!0);const U=Li(Q,{handle:z,connectionMode:t,fromNodeId:r,fromHandleId:o,fromType:s?"target":"source",isValidConnection:y,doc:k,lib:c,flowId:f,nodeLookup:u});E=U.handleDomNode,j=U.connection,m=qf(!!z,U.isValid);const ee=u.get(r),ne=ee?We(ee,L,G.Left,!0):Z.from,re={...Z,from:ne,isValid:m,to:U.toHandle&&m?ot({x:U.toHandle.x,y:U.toHandle.y},q):$,toHandle:U.toHandle,toPosition:m&&U.toHandle?U.toHandle.position:Yo[L.position],toNode:U.toHandle?u.get(U.toHandle.nodeId):null,pointer:$};p(re),Z=re}function J(Q){if(!("touches"in Q&&Q.touches.length>0)){if(N){(z||E)&&j&&m&&_?.(j);const{inProgress:q,...U}=Z,ee={...U,toPosition:Z.toHandle?Z.toPosition:null};w?.(Q,ee),i&&C?.(Q,ee)}h(),cancelAnimationFrame(F),P=!1,m=!1,j=null,E=null,k.removeEventListener("mousemove",X),k.removeEventListener("mouseup",J),k.removeEventListener("touchmove",X),k.removeEventListener("touchend",J)}}k.addEventListener("mousemove",X),k.addEventListener("mouseup",J),k.addEventListener("touchmove",X),k.addEventListener("touchend",J)}function Li(e,{handle:t,connectionMode:n,fromNodeId:o,fromHandleId:r,fromType:i,doc:s,lib:a,flowId:u,isValidConnection:c=Oi,nodeLookup:l}){const f=i==="target",d=t?s.querySelector(`.${a}-flow__handle[data-id="${u}-${t?.nodeId}-${t?.id}-${t?.type}"]`):null,{x:h,y:g}=me(e),_=s.elementFromPoint(h,g),w=_?.classList.contains(`${a}-flow__handle`)?_:d,y={handleDomNode:w,isValid:!1,connection:null,toHandle:null};if(w){const C=zi(void 0,w),p=w.getAttribute("data-nodeid"),v=w.getAttribute("data-handleid"),A=w.classList.contains("connectable"),S=w.classList.contains("connectableend");if(!p||!C)return y;const b={source:f?p:o,sourceHandle:f?v:r,target:f?o:p,targetHandle:f?r:v};y.connection=b;const k=A&&S&&(n===tt.Strict?f&&C==="source"||!f&&C==="target":p!==o||v!==r);y.isValid=k&&c(b),y.toHandle=Hi(p,C,v,l,n,!0)}return y}const Xn={onPointerDown:Gf,isValid:Li};function Uf({domNode:e,panZoom:t,getTransform:n,getViewScale:o}){const r=le(e);function i({translateExtent:a,width:u,height:c,zoomStep:l=1,pannable:f=!0,zoomable:d=!0,inversePan:h=!1}){const g=p=>{if(p.sourceEvent.type!=="wheel"||!t)return;const v=n(),A=p.sourceEvent.ctrlKey&&vt()?10:1,S=-p.sourceEvent.deltaY*(p.sourceEvent.deltaMode===1?.05:p.sourceEvent.deltaMode?1:.002)*l,b=v[2]*Math.pow(2,S*A);t.scaleTo(b)};let _=[0,0];const w=p=>{(p.sourceEvent.type==="mousedown"||p.sourceEvent.type==="touchstart")&&(_=[p.sourceEvent.clientX??p.sourceEvent.touches[0].clientX,p.sourceEvent.clientY??p.sourceEvent.touches[0].clientY])},y=p=>{const v=n();if(p.sourceEvent.type!=="mousemove"&&p.sourceEvent.type!=="touchmove"||!t)return;const A=[p.sourceEvent.clientX??p.sourceEvent.touches[0].clientX,p.sourceEvent.clientY??p.sourceEvent.touches[0].clientY],S=[A[0]-_[0],A[1]-_[1]];_=A;const b=o()*Math.max(v[2],Math.log(v[2]))*(h?-1:1),T={x:v[0]-S[0]*b,y:v[1]-S[1]*b},k=[[0,0],[u,c]];t.setViewportConstrained({x:T.x,y:T.y,zoom:v[2]},k,a)},C=di().on("start",w).on("zoom",f?y:null).on("zoom.wheel",d?g:null);r.call(C,{})}function s(){r.on("zoom",null)}return{update:i,destroy:s,pointer:he}}const un=e=>({x:e.x,y:e.y,zoom:e.k}),Cn=({x:e,y:t,zoom:n})=>sn.translate(e,t).scale(n),Ge=(e,t)=>e.target.closest(`.${t}`),Vi=(e,t)=>t===2&&Array.isArray(e)&&e.includes(2),Kf=e=>((e*=2)<=1?e*e*e:(e-=2)*e*e+2)/2,Nn=(e,t=0,n=Kf,o=()=>{})=>{const r=typeof t=="number"&&t>0;return r||o(),r?e.transition().duration(t).ease(n).on("end",o):e},Bi=e=>{const t=e.ctrlKey&&vt()?10:1;return-e.deltaY*(e.deltaMode===1?.05:e.deltaMode?1:.002)*t};function Qf({zoomPanValues:e,noWheelClassName:t,d3Selection:n,d3Zoom:o,panOnScrollMode:r,panOnScrollSpeed:i,zoomOnPinch:s,onPanZoomStart:a,onPanZoom:u,onPanZoomEnd:c}){return l=>{if(Ge(l,t))return l.ctrlKey&&l.preventDefault(),!1;l.preventDefault(),l.stopImmediatePropagation();const f=n.property("__zoom").k||1;if(l.ctrlKey&&s){const w=he(l),y=Bi(l),C=f*Math.pow(2,y);o.scaleTo(n,C,w,l);return}const d=l.deltaMode===1?20:1;let h=r===je.Vertical?0:l.deltaX*d,g=r===je.Horizontal?0:l.deltaY*d;!vt()&&l.shiftKey&&r!==je.Vertical&&(h=l.deltaY*d,g=0),o.translateBy(n,-(h/f)*i,-(g/f)*i,{internal:!0});const _=un(n.property("__zoom"));clearTimeout(e.panScrollTimeout),e.isPanScrolling?u?.(l,_):(e.isPanScrolling=!0,a?.(l,_)),e.panScrollTimeout=setTimeout(()=>{c?.(l,_),e.isPanScrolling=!1},150)}}function Jf({noWheelClassName:e,preventScrolling:t,d3ZoomHandler:n}){return function(o,r){const i=o.type==="wheel",s=!t&&i&&!o.ctrlKey,a=Ge(o,e);if(o.ctrlKey&&i&&a&&o.preventDefault(),s||a)return null;o.preventDefault(),n.call(this,o,r)}}function ed({zoomPanValues:e,onDraggingChange:t,onPanZoomStart:n}){return o=>{if(o.sourceEvent?.internal)return;const r=un(o.transform);e.mouseButton=o.sourceEvent?.button||0,e.isZoomingOrPanning=!0,e.prevViewport=r,o.sourceEvent?.type==="mousedown"&&t(!0),n&&n?.(o.sourceEvent,r)}}function td({zoomPanValues:e,panOnDrag:t,onPaneContextMenu:n,onTransformChange:o,onPanZoom:r}){return i=>{e.usedRightMouseButton=!!(n&&Vi(t,e.mouseButton??0)),i.sourceEvent?.sync||o([i.transform.x,i.transform.y,i.transform.k]),r&&!i.sourceEvent?.internal&&r?.(i.sourceEvent,un(i.transform))}}function nd({zoomPanValues:e,panOnDrag:t,panOnScroll:n,onDraggingChange:o,onPanZoomEnd:r,onPaneContextMenu:i}){return s=>{if(!s.sourceEvent?.internal&&(e.isZoomingOrPanning=!1,i&&Vi(t,e.mouseButton??0)&&!e.usedRightMouseButton&&s.sourceEvent&&i(s.sourceEvent),e.usedRightMouseButton=!1,o(!1),r)){const a=un(s.transform);e.prevViewport=a,clearTimeout(e.timerId),e.timerId=setTimeout(()=>{r?.(s.sourceEvent,a)},n?150:0)}}}function od({zoomActivationKeyPressed:e,zoomOnScroll:t,zoomOnPinch:n,panOnDrag:o,panOnScroll:r,zoomOnDoubleClick:i,userSelectionActive:s,noWheelClassName:a,noPanClassName:u,lib:c,connectionInProgress:l}){return f=>{const d=e||t,h=n&&f.ctrlKey,g=f.type==="wheel";if(f.button===1&&f.type==="mousedown"&&(Ge(f,`${c}-flow__node`)||Ge(f,`${c}-flow__edge`)))return!0;if(!o&&!d&&!r&&!i&&!n||s||l&&!g||Ge(f,a)&&g||Ge(f,u)&&(!g||r&&g&&!e)||!n&&f.ctrlKey&&g)return!1;if(!n&&f.type==="touchstart"&&f.touches?.length>1)return f.preventDefault(),!1;if(!d&&!r&&!h&&g||!o&&(f.type==="mousedown"||f.type==="touchstart")||Array.isArray(o)&&!o.includes(f.button)&&f.type==="mousedown")return!1;const _=Array.isArray(o)&&o.includes(f.button)||!f.button||f.button<=1;return(!f.ctrlKey||g)&&_}}function rd({domNode:e,minZoom:t,maxZoom:n,translateExtent:o,viewport:r,onPanZoom:i,onPanZoomStart:s,onPanZoomEnd:a,onDraggingChange:u}){const c={isZoomingOrPanning:!1,usedRightMouseButton:!1,prevViewport:{},mouseButton:0,timerId:void 0,panScrollTimeout:void 0,isPanScrolling:!1},l=e.getBoundingClientRect();let f=[[0,0],[l.width,l.height]];(typeof ResizeObserver<"u"?new ResizeObserver(O=>{const x=O[0];x&&(f=[[0,0],[x.contentRect.width,x.contentRect.height]])}):null)?.observe(e);const h=di().extent(()=>f).scaleExtent([t,n]).translateExtent(o),g=le(e).call(h);v({x:r.x,y:r.y,zoom:nt(r.zoom,t,n)},[[0,0],[l.width,l.height]],o);const _=g.on("wheel.zoom"),w=g.on("dblclick.zoom");h.wheelDelta(Bi);async function y(O,x){return g?new Promise(M=>{h?.interpolate(x?.interpolate==="linear"?ft:Ot).transform(Nn(g,x?.duration,x?.ease,()=>M(!0)),O)}):!1}function C({noWheelClassName:O,noPanClassName:x,onPaneContextMenu:M,userSelectionActive:N,panOnScroll:I,panOnDrag:$,panOnScrollMode:P,panOnScrollSpeed:j,preventScrolling:m,zoomOnPinch:E,zoomOnScroll:V,zoomOnDoubleClick:L,zoomActivationKeyPressed:Y,lib:W,onTransformChange:Z,connectionInProgress:H,paneClickDistance:X,selectionOnDrag:J}){N&&!c.isZoomingOrPanning&&p();const Q=I&&!Y&&!N;h.clickDistance(J?1/0:!pe(X)||X<0?0:X);const q=Q?Qf({zoomPanValues:c,noWheelClassName:O,d3Selection:g,d3Zoom:h,panOnScrollMode:P,panOnScrollSpeed:j,zoomOnPinch:E,onPanZoomStart:s,onPanZoom:i,onPanZoomEnd:a}):Jf({noWheelClassName:O,preventScrolling:m,d3ZoomHandler:_});g.on("wheel.zoom",q,{passive:!1});const U=ed({zoomPanValues:c,onDraggingChange:u,onPanZoomStart:s});h.on("start",U);const ee=td({zoomPanValues:c,panOnDrag:$,onPaneContextMenu:!!M,onPanZoom:i,onTransformChange:Z});h.on("zoom",ee);const ne=nd({zoomPanValues:c,panOnDrag:$,panOnScroll:I,onPaneContextMenu:M,onPanZoomEnd:a,onDraggingChange:u});h.on("end",ne);const re=od({zoomActivationKeyPressed:Y,panOnDrag:$,zoomOnScroll:V,panOnScroll:I,zoomOnDoubleClick:L,zoomOnPinch:E,userSelectionActive:N,noPanClassName:x,noWheelClassName:O,lib:W,connectionInProgress:H});h.filter(re),L?g.on("dblclick.zoom",w):g.on("dblclick.zoom",null)}function p(){h.on("zoom",null)}async function v(O,x,M){const N=Cn(O),I=h?.constrain()(N,x,M);return I&&await y(I),I}async function A(O,x){const M=Cn(O);return await y(M,x),M}function S(O){if(g){const x=Cn(O),M=g.property("__zoom");(M.k!==O.zoom||M.x!==O.x||M.y!==O.y)&&h?.transform(g,x,null,{sync:!0})}}function b(){const O=g?fi(g.node()):{x:0,y:0,k:1};return{x:O.x,y:O.y,zoom:O.k}}async function T(O,x){return g?new Promise(M=>{h?.interpolate(x?.interpolate==="linear"?ft:Ot).scaleTo(Nn(g,x?.duration,x?.ease,()=>M(!0)),O)}):!1}async function k(O,x){return g?new Promise(M=>{h?.interpolate(x?.interpolate==="linear"?ft:Ot).scaleBy(Nn(g,x?.duration,x?.ease,()=>M(!0)),O)}):!1}function F(O){h?.scaleExtent(O)}function z(O){h?.translateExtent(O)}function B(O){const x=!pe(O)||O<0?0:O;h?.clickDistance(x)}return{update:C,destroy:p,setViewport:A,setViewportConstrained:v,getViewport:b,scaleTo:T,scaleBy:k,setScaleExtent:F,setTranslateExtent:z,syncViewport:S,setClickDistance:B}}var rt;(function(e){e.Line="line",e.Handle="handle"})(rt||(rt={}));function id({width:e,prevWidth:t,height:n,prevHeight:o,affectsX:r,affectsY:i}){const s=e-t,a=n-o,u=[s>0?1:s<0?-1:0,a>0?1:a<0?-1:0];return s&&r&&(u[0]=u[0]*-1),a&&i&&(u[1]=u[1]*-1),u}function or(e){const t=e.includes("right")||e.includes("left"),n=e.includes("bottom")||e.includes("top"),o=e.includes("left"),r=e.includes("top");return{isHorizontal:t,isVertical:n,affectsX:o,affectsY:r}}function Re(e,t){return Math.max(0,t-e)}function Pe(e,t){return Math.max(0,e-t)}function $t(e,t,n){return Math.max(0,t-e,e-n)}function rr(e,t){return e?!t:t}function sd(e,t,n,o,r,i,s,a){let{affectsX:u,affectsY:c}=t;const{isHorizontal:l,isVertical:f}=t,d=l&&f,{xSnapped:h,ySnapped:g}=n,{minWidth:_,maxWidth:w,minHeight:y,maxHeight:C}=o,{x:p,y:v,width:A,height:S,aspectRatio:b}=e;let T=Math.floor(l?h-e.pointerX:0),k=Math.floor(f?g-e.pointerY:0);const F=A+(u?-T:T),z=S+(c?-k:k),B=-i[0]*A,O=-i[1]*S;let x=$t(F,_,w),M=$t(z,y,C);if(s){let $=0,P=0;u&&T<0?$=Re(p+T+B,s[0][0]):!u&&T>0&&($=Pe(p+F+B,s[1][0])),c&&k<0?P=Re(v+k+O,s[0][1]):!c&&k>0&&(P=Pe(v+z+O,s[1][1])),x=Math.max(x,$),M=Math.max(M,P)}if(a){let $=0,P=0;u&&T>0?$=Pe(p+T,a[0][0]):!u&&T<0&&($=Re(p+F,a[1][0])),c&&k>0?P=Pe(v+k,a[0][1]):!c&&k<0&&(P=Re(v+z,a[1][1])),x=Math.max(x,$),M=Math.max(M,P)}if(r){if(l){const $=$t(F/b,y,C)*b;if(x=Math.max(x,$),s){let P=0;!u&&!c||u&&!c&&d?P=Pe(v+O+F/b,s[1][1])*b:P=Re(v+O+(u?T:-T)/b,s[0][1])*b,x=Math.max(x,P)}if(a){let P=0;!u&&!c||u&&!c&&d?P=Re(v+F/b,a[1][1])*b:P=Pe(v+(u?T:-T)/b,a[0][1])*b,x=Math.max(x,P)}}if(f){const $=$t(z*b,_,w)/b;if(M=Math.max(M,$),s){let P=0;!u&&!c||c&&!u&&d?P=Pe(p+z*b+B,s[1][0])/b:P=Re(p+(c?k:-k)*b+B,s[0][0])/b,M=Math.max(M,P)}if(a){let P=0;!u&&!c||c&&!u&&d?P=Re(p+z*b,a[1][0])/b:P=Pe(p+(c?k:-k)*b,a[0][0])/b,M=Math.max(M,P)}}}k=k+(k<0?M:-M),T=T+(T<0?x:-x),r&&(d?F>z*b?k=(rr(u,c)?-T:T)/b:T=(rr(u,c)?-k:k)*b:l?(k=T/b,c=u):(T=k*b,u=c));const N=u?p+T:p,I=c?v+k:v;return{width:A+(u?-T:T),height:S+(c?-k:k),x:i[0]*T*(u?-1:1)+N,y:i[1]*k*(c?-1:1)+I}}const ji={width:0,height:0,x:0,y:0},ad={...ji,pointerX:0,pointerY:0,aspectRatio:1};function cd(e,t,n){const o=t.position.x+e.position.x,r=t.position.y+e.position.y,i=e.measured.width??0,s=e.measured.height??0,a=n[0]*i,u=n[1]*s;return[[o-a,r-u],[o+i-a,r+s-u]]}function ud({domNode:e,nodeId:t,getStoreItems:n,onChange:o,onEnd:r}){const i=le(e);let s={controlDirection:or("bottom-right"),boundaries:{minWidth:0,minHeight:0,maxWidth:Number.MAX_VALUE,maxHeight:Number.MAX_VALUE},resizeDirection:void 0,keepAspectRatio:!1};function a({controlPosition:c,boundaries:l,keepAspectRatio:f,resizeDirection:d,onResizeStart:h,onResize:g,onResizeEnd:_,shouldResize:w}){let y={...ji},C={...ad};s={boundaries:l,resizeDirection:d,keepAspectRatio:f,controlDirection:or(c)};let p,v=null,A=[],S,b,T,k=!1;const F=Kr().on("start",z=>{const{nodeLookup:B,transform:O,snapGrid:x,snapToGrid:M,nodeOrigin:N,paneDomNode:I}=n();if(p=B.get(t),!p)return;v=I?.getBoundingClientRect()??null;const{xSnapped:$,ySnapped:P}=dt(z.sourceEvent,{transform:O,snapGrid:x,snapToGrid:M,containerBounds:v});y={width:p.measured.width??0,height:p.measured.height??0,x:p.position.x??0,y:p.position.y??0},C={...y,pointerX:$,pointerY:P,aspectRatio:y.width/y.height},S=void 0,b=Ze(p.extent)?p.extent:void 0,p.parentId&&(p.extent==="parent"||p.expandParent)&&(S=B.get(p.parentId)),S&&p.extent==="parent"&&(b=[[0,0],[S.measured.width,S.measured.height]]),A=[],T=void 0;for(const[j,m]of B)if(m.parentId===t&&(A.push({id:j,position:{...m.position},extent:m.extent}),m.extent==="parent"||m.expandParent)){const E=cd(m,p,m.origin??N);T?T=[[Math.min(E[0][0],T[0][0]),Math.min(E[0][1],T[0][1])],[Math.max(E[1][0],T[1][0]),Math.max(E[1][1],T[1][1])]]:T=E}h?.(z,{...y})}).on("drag",z=>{const{transform:B,snapGrid:O,snapToGrid:x,nodeOrigin:M}=n(),N=dt(z.sourceEvent,{transform:B,snapGrid:O,snapToGrid:x,containerBounds:v}),I=[];if(!p)return;const{x:$,y:P,width:j,height:m}=y,E={},V=p.origin??M,{width:L,height:Y,x:W,y:Z}=sd(C,s.controlDirection,N,s.boundaries,s.keepAspectRatio,V,b,T),H=L!==j,X=Y!==m,J=W!==$&&H,Q=Z!==P&&X;if(!J&&!Q&&!H&&!X)return;if((J||Q||V[0]===1||V[1]===1)&&(E.x=J?W:y.x,E.y=Q?Z:y.y,y.x=E.x,y.y=E.y,A.length>0)){const ne=W-$,re=Z-P;for(const ce of A)ce.position={x:ce.position.x-ne+V[0]*(L-j),y:ce.position.y-re+V[1]*(Y-m)},I.push(ce)}if((H||X)&&(E.width=H&&(!s.resizeDirection||s.resizeDirection==="horizontal")?L:y.width,E.height=X&&(!s.resizeDirection||s.resizeDirection==="vertical")?Y:y.height,y.width=E.width,y.height=E.height),S&&p.expandParent){const ne=V[0]*(E.width??0);E.x&&E.x{k&&(_?.(z,{...y}),r?.({...y}),k=!1)});i.call(F)}function u(){i.on(".drag",null)}return{update:a,destroy:u}}var Mn={exports:{}},An={},In={exports:{}},Tn={};var ir;function ld(){if(ir)return Tn;ir=1;var e=en();function t(f,d){return f===d&&(f!==0||1/f===1/d)||f!==f&&d!==d}var n=typeof Object.is=="function"?Object.is:t,o=e.useState,r=e.useEffect,i=e.useLayoutEffect,s=e.useDebugValue;function a(f,d){var h=d(),g=o({inst:{value:h,getSnapshot:d}}),_=g[0].inst,w=g[1];return i(function(){_.value=h,_.getSnapshot=d,u(_)&&w({inst:_})},[f,h,d]),r(function(){return u(_)&&w({inst:_}),f(function(){u(_)&&w({inst:_})})},[f]),s(h),h}function u(f){var d=f.getSnapshot;f=f.value;try{var h=d();return!n(f,h)}catch{return!0}}function c(f,d){return d()}var l=typeof window>"u"||typeof window.document>"u"||typeof window.document.createElement>"u"?c:a;return Tn.useSyncExternalStore=e.useSyncExternalStore!==void 0?e.useSyncExternalStore:l,Tn}var sr;function fd(){return sr||(sr=1,In.exports=ld()),In.exports}var ar;function dd(){if(ar)return An;ar=1;var e=en(),t=fd();function n(c,l){return c===l&&(c!==0||1/c===1/l)||c!==c&&l!==l}var o=typeof Object.is=="function"?Object.is:n,r=t.useSyncExternalStore,i=e.useRef,s=e.useEffect,a=e.useMemo,u=e.useDebugValue;return An.useSyncExternalStoreWithSelector=function(c,l,f,d,h){var g=i(null);if(g.current===null){var _={hasValue:!1,value:null};g.current=_}else _=g.current;g=a(function(){function y(S){if(!C){if(C=!0,p=S,S=d(S),h!==void 0&&_.hasValue){var b=_.value;if(h(b,S))return v=b}return v=S}if(b=v,o(p,S))return b;var T=d(S);return h!==void 0&&h(b,T)?(p=S,b):(p=S,v=T)}var C=!1,p,v,A=f===void 0?null:f;return[function(){return y(l())},A===null?void 0:function(){return y(A())}]},[l,f,d,h]);var w=r(c,g[0],g[1]);return s(function(){_.hasValue=!0,_.value=w},[w]),u(w),w},An}var cr;function hd(){return cr||(cr=1,Mn.exports=dd()),Mn.exports}var gd=hd();const pd=Hr(gd),md={},ur=e=>{let t;const n=new Set,o=(l,f)=>{const d=typeof l=="function"?l(t):l;if(!Object.is(d,t)){const h=t;t=f??(typeof d!="object"||d===null)?d:Object.assign({},t,d),n.forEach(g=>g(t,h))}},r=()=>t,u={setState:o,getState:r,getInitialState:()=>c,subscribe:l=>(n.add(l),()=>n.delete(l)),destroy:()=>{(md?"production":void 0)!=="production"&&console.warn("[DEPRECATED] The `destroy` method will be unsupported in a future version. Instead use unsubscribe function returned by subscribe. Everything will be garbage-collected if store is garbage-collected."),n.clear()}},c=t=e(o,r,u);return u},yd=e=>e?ur(e):ur,{useDebugValue:xd}=Ta,{useSyncExternalStoreWithSelector:wd}=pd,vd=e=>e;function Fi(e,t=vd,n){const o=wd(e.subscribe,e.getState,e.getServerState||e.getInitialState,t,n);return xd(o),o}const lr=(e,t)=>{const n=yd(e),o=(r,i=t)=>Fi(n,r,i);return Object.assign(o,n),o},_d=(e,t)=>e?lr(e,t):lr;function ie(e,t){if(Object.is(e,t))return!0;if(typeof e!="object"||e===null||typeof t!="object"||t===null)return!1;if(e instanceof Map&&t instanceof Map){if(e.size!==t.size)return!1;for(const[o,r]of e)if(!Object.is(r,t.get(o)))return!1;return!0}if(e instanceof Set&&t instanceof Set){if(e.size!==t.size)return!1;for(const o of e)if(!t.has(o))return!1;return!0}const n=Object.keys(e);if(n.length!==Object.keys(t).length)return!1;for(const o of n)if(!Object.prototype.hasOwnProperty.call(t,o)||!Object.is(e[o],t[o]))return!1;return!0}var Bg=Ra();const ln=D.createContext(null),Ed=ln.Provider,Yi=ye.error001("react");function te(e,t){const n=D.useContext(ln);if(n===null)throw new Error(Yi);return Fi(n,e,t)}function oe(){const e=D.useContext(ln);if(e===null)throw new Error(Yi);return D.useMemo(()=>({getState:e.getState,setState:e.setState,subscribe:e.subscribe}),[e])}const fr={display:"none"},bd={position:"absolute",width:1,height:1,margin:-1,border:0,padding:0,overflow:"hidden",clip:"rect(0px, 0px, 0px, 0px)",clipPath:"inset(100%)"},Xi="react-flow__node-desc",Zi="react-flow__edge-desc",Sd="react-flow__aria-live",Cd=e=>e.ariaLiveMessage,Nd=e=>e.ariaLabelConfig;function Md({rfId:e}){const t=te(Cd);return R.jsx("div",{id:`${Sd}-${e}`,"aria-live":"assertive","aria-atomic":"true",style:bd,children:t})}function Ad({rfId:e,disableKeyboardA11y:t}){const n=te(Nd);return R.jsxs(R.Fragment,{children:[R.jsx("div",{id:`${Xi}-${e}`,style:fr,children:t?n["node.a11yDescription.default"]:n["node.a11yDescription.keyboardDisabled"]}),R.jsx("div",{id:`${Zi}-${e}`,style:fr,children:n["edge.a11yDescription.default"]}),!t&&R.jsx(Md,{rfId:e})]})}const fn=D.forwardRef(({position:e="top-left",children:t,className:n,style:o,...r},i)=>{const s=`${e}`.split("-");return R.jsx("div",{className:se(["react-flow__panel",n,...s]),style:o,ref:i,...r,children:t})});fn.displayName="Panel";const dr="https://reactflow.dev?utm_source=attribution";function Id({proOptions:e,position:t="bottom-right"}){return e?.hideAttribution?null:R.jsx(fn,{position:t,className:"react-flow__attribution","data-message":`Please only hide this attribution when you are subscribed to React Flow Pro: ${dr}`,children:R.jsx("a",{href:dr,target:"_blank",rel:"noopener noreferrer","aria-label":"React Flow attribution",children:"React Flow"})})}const Td=e=>{const t=[],n=[];for(const[,o]of e.nodeLookup)o.selected&&t.push(o.internals.userNode);for(const[,o]of e.edgeLookup)o.selected&&n.push(o);return{selectedNodes:t,selectedEdges:n}},Dt=e=>e.id;function kd(e,t){return ie(e.selectedNodes.map(Dt),t.selectedNodes.map(Dt))&&ie(e.selectedEdges.map(Dt),t.selectedEdges.map(Dt))}function Rd({onSelectionChange:e}){const t=oe(),{selectedNodes:n,selectedEdges:o}=te(Td,kd);return D.useEffect(()=>{const r={nodes:n,edges:o};e?.(r),t.getState().onSelectionChangeHandlers.forEach(i=>i(r))},[n,o,e]),null}const Pd=e=>!!e.onSelectionChangeHandlers;function $d({onSelectionChange:e}){const t=te(Pd);return e||t?R.jsx(Rd,{onSelectionChange:e}):null}const Wi=[0,0],Dd={x:0,y:0,zoom:1},Hd=["nodes","edges","defaultNodes","defaultEdges","onConnect","onConnectStart","onConnectEnd","onClickConnectStart","onClickConnectEnd","nodesDraggable","autoPanOnNodeFocus","nodesConnectable","nodesFocusable","edgesFocusable","edgesReconnectable","elevateNodesOnSelect","elevateEdgesOnSelect","minZoom","maxZoom","nodeExtent","onNodesChange","onEdgesChange","elementsSelectable","connectionMode","snapGrid","snapToGrid","translateExtent","connectOnClick","defaultEdgeOptions","fitView","fitViewOptions","onNodesDelete","onEdgesDelete","onDelete","onNodeDrag","onNodeDragStart","onNodeDragStop","onSelectionDrag","onSelectionDragStart","onSelectionDragStop","onMoveStart","onMove","onMoveEnd","noPanClassName","nodeOrigin","autoPanOnConnect","autoPanOnNodeDrag","onError","connectionRadius","isValidConnection","selectNodesOnDrag","nodeDragThreshold","connectionDragThreshold","onBeforeDelete","debug","autoPanSpeed","ariaLabelConfig","zIndexMode"],hr=[...Hd,"rfId"],zd=e=>({setNodes:e.setNodes,setEdges:e.setEdges,setMinZoom:e.setMinZoom,setMaxZoom:e.setMaxZoom,setTranslateExtent:e.setTranslateExtent,setNodeExtent:e.setNodeExtent,reset:e.reset,setDefaultNodesAndEdges:e.setDefaultNodesAndEdges}),gr={translateExtent:yt,nodeOrigin:Wi,minZoom:.5,maxZoom:2,elementsSelectable:!0,noPanClassName:"nopan",rfId:"1"};function Od(e){const{setNodes:t,setEdges:n,setMinZoom:o,setMaxZoom:r,setTranslateExtent:i,setNodeExtent:s,reset:a,setDefaultNodesAndEdges:u}=te(zd,ie),c=oe();D.useEffect(()=>(u(e.defaultNodes,e.defaultEdges),()=>{l.current=gr,a()}),[]);const l=D.useRef(gr);return D.useEffect(()=>{for(const f of hr){const d=e[f],h=l.current[f];d!==h&&(typeof e[f]>"u"||(f==="nodes"?t(d):f==="edges"?n(d):f==="minZoom"?o(d):f==="maxZoom"?r(d):f==="translateExtent"?i(d):f==="nodeExtent"?s(d):f==="ariaLabelConfig"?c.setState({ariaLabelConfig:Ef(d)}):f==="fitView"?c.setState({fitViewQueued:d}):f==="fitViewOptions"?c.setState({fitViewOptions:d}):c.setState({[f]:d})))}l.current=e},hr.map(f=>e[f])),null}function pr(){return typeof window>"u"||!window.matchMedia?null:window.matchMedia("(prefers-color-scheme: dark)")}function Ld(e){const[t,n]=D.useState(e==="system"?null:e);return D.useEffect(()=>{if(e!=="system"){n(e);return}const o=pr(),r=()=>n(o?.matches?"dark":"light");return r(),o?.addEventListener("change",r),()=>{o?.removeEventListener("change",r)}},[e]),t!==null?t:pr()?.matches?"dark":"light"}const mr=typeof document<"u"?document:null;function _t(e=null,t={target:mr,actInsideInputWithModifier:!0}){const[n,o]=D.useState(!1),r=D.useRef(!1),i=D.useRef(new Set([])),[s,a]=D.useMemo(()=>{if(e!==null){const c=(Array.isArray(e)?e:[e]).filter(f=>typeof f=="string").map(f=>f.replace("+",` +`).replace(` + +`,` ++`).split(` +`)),l=c.reduce((f,d)=>f.concat(...d),[]);return[c,l]}return[[],[]]},[e]);return D.useEffect(()=>{const u=t?.target??mr,c=t?.actInsideInputWithModifier??!0;if(e!==null){const l=h=>{if(r.current=h.ctrlKey||h.metaKey||h.shiftKey||h.altKey,(!r.current||r.current&&!c)&&Ni(h))return!1;const _=xr(h.code,a);if(i.current.add(h[_]),yr(s,i.current,!1)){const w=h.composedPath?.()?.[0]||h.target,y=w?.nodeName==="BUTTON"||w?.nodeName==="A";t.preventDefault!==!1&&(r.current||!y)&&h.preventDefault(),o(!0)}},f=h=>{const g=xr(h.code,a);yr(s,i.current,!0)?(o(!1),i.current.clear()):i.current.delete(h[g]),h.key==="Meta"&&i.current.clear(),r.current=!1},d=()=>{i.current.clear(),o(!1)};return u?.addEventListener("keydown",l),u?.addEventListener("keyup",f),window.addEventListener("blur",d),window.addEventListener("contextmenu",d),()=>{u?.removeEventListener("keydown",l),u?.removeEventListener("keyup",f),window.removeEventListener("blur",d),window.removeEventListener("contextmenu",d)}}},[e,o]),n}function yr(e,t,n){return e.filter(o=>n||o.length===t.size).some(o=>o.every(r=>t.has(r)))}function xr(e,t){return t.includes(e)?"code":"key"}const Vd=()=>{const e=oe();return D.useMemo(()=>({zoomIn:async t=>{const{panZoom:n}=e.getState();return n?n.scaleBy(1.2,t):!1},zoomOut:async t=>{const{panZoom:n}=e.getState();return n?n.scaleBy(1/1.2,t):!1},zoomTo:async(t,n)=>{const{panZoom:o}=e.getState();return o?o.scaleTo(t,n):!1},getZoom:()=>e.getState().transform[2],setViewport:async(t,n)=>{const{transform:[o,r,i],panZoom:s}=e.getState();return s?(await s.setViewport({x:t.x??o,y:t.y??r,zoom:t.zoom??i},n),!0):!1},getViewport:()=>{const[t,n,o]=e.getState().transform;return{x:t,y:n,zoom:o}},setCenter:async(t,n,o)=>e.getState().setCenter(t,n,o),fitBounds:async(t,n)=>{const{width:o,height:r,minZoom:i,maxZoom:s,panZoom:a}=e.getState(),u=oo(t,o,r,i,s,n?.padding??.1);return a?(await a.setViewport(u,{duration:n?.duration,ease:n?.ease,interpolate:n?.interpolate}),!0):!1},screenToFlowPosition:(t,n={})=>{const{transform:o,snapGrid:r,snapToGrid:i,domNode:s}=e.getState();if(!s)return t;const{x:a,y:u}=s.getBoundingClientRect(),c={x:t.x-a,y:t.y-u},l=n.snapGrid??r,f=n.snapToGrid??i;return Mt(c,o,f,l)},flowToScreenPosition:t=>{const{transform:n,domNode:o}=e.getState();if(!o)return t;const{x:r,y:i}=o.getBoundingClientRect(),s=ot(t,n);return{x:s.x+r,y:s.y+i}}}),[])};function qi(e,t){const n=[],o=new Map,r=[];for(const i of e)if(i.type==="add"){r.push(i);continue}else if(i.type==="remove"||i.type==="replace")o.set(i.id,[i]);else{const s=o.get(i.id);s?s.push(i):o.set(i.id,[i])}for(const i of t){const s=o.get(i.id);if(!s){n.push(i);continue}if(s[0].type==="remove")continue;if(s[0].type==="replace"){n.push({...s[0].item});continue}const a={...i};for(const u of s)Bd(u,a);n.push(a)}return r.length&&r.forEach(i=>{i.index!==void 0?n.splice(i.index,0,{...i.item}):n.push({...i.item})}),n}function Bd(e,t){switch(e.type){case"select":{t.selected=e.selected;break}case"position":{typeof e.position<"u"&&(t.position=e.position),typeof e.dragging<"u"&&(t.dragging=e.dragging);break}case"dimensions":{typeof e.dimensions<"u"&&(t.measured={...e.dimensions},e.setAttributes&&((e.setAttributes===!0||e.setAttributes==="width")&&(t.width=e.dimensions.width),(e.setAttributes===!0||e.setAttributes==="height")&&(t.height=e.dimensions.height))),typeof e.resizing=="boolean"&&(t.resizing=e.resizing);break}}}function jd(e,t){return qi(e,t)}function Fd(e,t){return qi(e,t)}function Le(e,t){return{id:e,type:"select",selected:t}}function Ue(e,t=new Set,n=!1){const o=[];for(const[r,i]of e){const s=t.has(r);!(i.selected===void 0&&!s)&&i.selected!==s&&(n&&(i.selected=s),o.push(Le(i.id,s)))}return o}function wr({items:e=[],lookup:t}){const n=[],o=new Map(e.map(r=>[r.id,r]));for(const[r,i]of e.entries()){const s=t.get(i.id),a=s?.internals?.userNode??s;a!==void 0&&a!==i&&n.push({id:i.id,item:i,type:"replace"}),a===void 0&&n.push({item:i,type:"add",index:r})}for(const[r]of t)o.get(r)===void 0&&n.push({id:r,type:"remove"});return n}function vr(e){return{id:e.id,type:"remove"}}const Yd=Ei();function Xd(e,t,n={}){return Af(e,t,{...n,onError:n.onError??Yd})}const _r=e=>hf(e),Zd=e=>yi(e);function Gi(e){return D.forwardRef(e)}const Ui=typeof window<"u"?D.useLayoutEffect:D.useEffect;function Er(e){const[t,n]=D.useState(BigInt(0)),[o]=D.useState(()=>Wd(()=>n(r=>r+BigInt(1))));return Ui(()=>{const r=o.get();r.length&&(e(r),o.reset())},[t]),o}function Wd(e){let t=[];return{get:()=>t,reset:()=>{t=[]},push:n=>{t.push(n),e()}}}const Ki=D.createContext(null);function qd({children:e}){const t=oe(),n=D.useCallback(a=>{const{nodes:u=[],setNodes:c,hasDefaultNodes:l,onNodesChange:f,nodeLookup:d,fitViewQueued:h,onNodesChangeMiddlewareMap:g}=t.getState();let _=u;for(const y of a)_=typeof y=="function"?y(_):y;let w=wr({items:_,lookup:d});for(const y of g.values())w=y(w);l&&c(_),w.length>0?f?.(w):h&&window.requestAnimationFrame(()=>{const{fitViewQueued:y,nodes:C,setNodes:p}=t.getState();y&&p(C)})},[]),o=Er(n),r=D.useCallback(a=>{const{edges:u=[],setEdges:c,hasDefaultEdges:l,onEdgesChange:f,edgeLookup:d}=t.getState();let h=u;for(const g of a)h=typeof g=="function"?g(h):g;l?c(h):f&&f(wr({items:h,lookup:d}))},[]),i=Er(r),s=D.useMemo(()=>({nodeQueue:o,edgeQueue:i}),[]);return R.jsx(Ki.Provider,{value:s,children:e})}function Gd(){const e=D.useContext(Ki);if(!e)throw new Error("useBatchContext must be used within a BatchProvider");return e}const Ud=e=>!!e.panZoom;function lo(){const e=Vd(),t=oe(),n=Gd(),o=te(Ud),r=D.useMemo(()=>{const i=f=>t.getState().nodeLookup.get(f),s=f=>{n.nodeQueue.push(f)},a=f=>{n.edgeQueue.push(f)},u=f=>{const{nodeLookup:d,nodeOrigin:h}=t.getState(),g=_r(f)?f:d.get(f.id),_=g.parentId?Si(g.position,g.measured,g.parentId,d,h):g.position,w={...g,position:_,width:g.measured?.width??g.width,height:g.measured?.height??g.height};return wt(w)},c=(f,d,h={replace:!1})=>{s(g=>g.map(_=>{if(_.id===f){const w=typeof d=="function"?d(_):d;return h.replace&&_r(w)?w:{..._,...w}}return _}))},l=(f,d,h={replace:!1})=>{a(g=>g.map(_=>{if(_.id===f){const w=typeof d=="function"?d(_):d;return h.replace&&Zd(w)?w:{..._,...w}}return _}))};return{getNodes:()=>t.getState().nodes.map(f=>({...f})),getNode:f=>i(f)?.internals.userNode,getInternalNode:i,getEdges:()=>{const{edges:f=[]}=t.getState();return f.map(d=>({...d}))},getEdge:f=>t.getState().edgeLookup.get(f),setNodes:s,setEdges:a,addNodes:f=>{const d=Array.isArray(f)?f:[f];n.nodeQueue.push(h=>[...h,...d])},addEdges:f=>{const d=Array.isArray(f)?f:[f];n.edgeQueue.push(h=>[...h,...d])},toObject:()=>{const{nodes:f=[],edges:d=[],transform:h}=t.getState(),[g,_,w]=h;return{nodes:f.map(y=>({...y})),edges:d.map(y=>({...y})),viewport:{x:g,y:_,zoom:w}}},deleteElements:async({nodes:f=[],edges:d=[]})=>{const{nodes:h,edges:g,onNodesDelete:_,onEdgesDelete:w,triggerNodeChanges:y,triggerEdgeChanges:C,onDelete:p,onBeforeDelete:v}=t.getState(),{nodes:A,edges:S}=await xf({nodesToRemove:f,edgesToRemove:d,nodes:h,edges:g,onBeforeDelete:v}),b=S.length>0,T=A.length>0;if(b){const k=S.map(vr);w?.(S),C(k)}if(T){const k=A.map(vr);_?.(A),y(k)}return(T||b)&&p?.({nodes:A,edges:S}),{deletedNodes:A,deletedEdges:S}},getIntersectingNodes:(f,d=!0,h)=>{const g=Zo(f),_=g?f:u(f),w=h!==void 0;return _?(h||t.getState().nodes).filter(y=>{const C=t.getState().nodeLookup.get(y.id);if(C&&!g&&(y.id===f.id||!C.internals.positionAbsolute))return!1;const p=wt(w?y:C),v=Kt(p,_);return d&&v>0||v>=p.width*p.height||v>=_.width*_.height}):[]},isNodeIntersecting:(f,d,h=!0)=>{const _=Zo(f)?f:u(f);if(!_)return!1;const w=Kt(_,d);return h&&w>0||w>=d.width*d.height||w>=_.width*_.height},updateNode:c,updateNodeData:(f,d,h={replace:!1})=>{c(f,g=>{const _=typeof d=="function"?d(g):d;return h.replace?{...g,data:_}:{...g,data:{...g.data,..._}}},h)},updateEdge:l,updateEdgeData:(f,d,h={replace:!1})=>{l(f,g=>{const _=typeof d=="function"?d(g):d;return h.replace?{...g,data:_}:{...g,data:{...g.data,..._}}},h)},getNodesBounds:f=>{const{nodeLookup:d,nodeOrigin:h}=t.getState();return gf(f,{nodeLookup:d,nodeOrigin:h})},getHandleConnections:({type:f,id:d,nodeId:h})=>Array.from(t.getState().connectionLookup.get(`${h}-${f}${d?`-${d}`:""}`)?.values()??[]),getNodeConnections:({type:f,handleId:d,nodeId:h})=>Array.from(t.getState().connectionLookup.get(`${h}${f?d?`-${f}-${d}`:`-${f}`:""}`)?.values()??[]),fitView:async f=>{const d=t.getState().fitViewResolver??_f();return t.setState({fitViewQueued:!0,fitViewOptions:f,fitViewResolver:d}),n.nodeQueue.push(h=>[...h]),d.promise}}},[]);return D.useMemo(()=>({...r,...e,viewportInitialized:o}),[o])}const br=e=>e.selected,Kd=typeof window<"u"?window:void 0;function Qd({deleteKeyCode:e,multiSelectionKeyCode:t}){const n=oe(),{deleteElements:o}=lo(),r=_t(e,{actInsideInputWithModifier:!1}),i=_t(t,{target:Kd});D.useEffect(()=>{if(r){const{edges:s,nodes:a}=n.getState();o({nodes:a.filter(br),edges:s.filter(br)}),n.setState({nodesSelectionActive:!1})}},[r]),D.useEffect(()=>{n.setState({multiSelectionActive:i})},[i])}function Jd(e){const t=oe();D.useEffect(()=>{const n=()=>{if(!e.current||!(e.current.checkVisibility?.()??!0))return!1;const o=ro(e.current);(o.height===0||o.width===0)&&t.getState().onError?.("004",ye.error004()),t.setState({width:o.width||500,height:o.height||500})};if(e.current){n(),window.addEventListener("resize",n);const o=new ResizeObserver(()=>n());return o.observe(e.current),()=>{window.removeEventListener("resize",n),o&&e.current&&o.unobserve(e.current)}}},[])}const dn={position:"absolute",width:"100%",height:"100%",top:0,left:0},eh=e=>({userSelectionActive:e.userSelectionActive,lib:e.lib,connectionInProgress:e.connection.inProgress});function th({onPaneContextMenu:e,zoomOnScroll:t=!0,zoomOnPinch:n=!0,panOnScroll:o=!1,panOnScrollSpeed:r=.5,panOnScrollMode:i=je.Free,zoomOnDoubleClick:s=!0,panOnDrag:a=!0,defaultViewport:u,translateExtent:c,minZoom:l,maxZoom:f,zoomActivationKeyCode:d,preventScrolling:h=!0,children:g,noWheelClassName:_,noPanClassName:w,onViewportChange:y,isControlledViewport:C,paneClickDistance:p,selectionOnDrag:v}){const A=oe(),S=D.useRef(null),{userSelectionActive:b,lib:T,connectionInProgress:k}=te(eh,ie),F=_t(d),z=D.useRef();Jd(S);const B=D.useCallback(O=>{y?.({x:O[0],y:O[1],zoom:O[2]}),C||A.setState({transform:O})},[y,C]);return D.useEffect(()=>{if(S.current){z.current=rd({domNode:S.current,minZoom:l,maxZoom:f,translateExtent:c,viewport:u,onDraggingChange:N=>A.setState(I=>I.paneDragging===N?I:{paneDragging:N}),onPanZoomStart:(N,I)=>{const{onViewportChangeStart:$,onMoveStart:P}=A.getState();P?.(N,I),$?.(I)},onPanZoom:(N,I)=>{const{onViewportChange:$,onMove:P}=A.getState();P?.(N,I),$?.(I)},onPanZoomEnd:(N,I)=>{const{onViewportChangeEnd:$,onMoveEnd:P}=A.getState();P?.(N,I),$?.(I)}});const{x:O,y:x,zoom:M}=z.current.getViewport();return A.setState({panZoom:z.current,transform:[O,x,M],domNode:S.current.closest(".react-flow")}),()=>{z.current?.destroy()}}},[]),D.useEffect(()=>{z.current?.update({onPaneContextMenu:e,zoomOnScroll:t,zoomOnPinch:n,panOnScroll:o,panOnScrollSpeed:r,panOnScrollMode:i,zoomOnDoubleClick:s,panOnDrag:a,zoomActivationKeyPressed:F,preventScrolling:h,noPanClassName:w,userSelectionActive:b,noWheelClassName:_,lib:T,onTransformChange:B,connectionInProgress:k,selectionOnDrag:v,paneClickDistance:p})},[e,t,n,o,r,i,s,a,F,h,w,b,_,T,B,k,v,p]),R.jsx("div",{className:"react-flow__renderer",ref:S,style:dn,children:g})}const nh=e=>({userSelectionActive:e.userSelectionActive,userSelectionRect:e.userSelectionRect});function oh(){const{userSelectionActive:e,userSelectionRect:t}=te(nh,ie);return e&&t?R.jsx("div",{className:"react-flow__selection react-flow__container",style:{width:t.width,height:t.height,transform:`translate(${t.x}px, ${t.y}px)`}}):null}const kn=(e,t)=>n=>{n.target===t.current&&e?.(n)},rh=e=>({userSelectionActive:e.userSelectionActive,elementsSelectable:e.elementsSelectable,dragging:e.paneDragging,panBy:e.panBy,autoPanSpeed:e.autoPanSpeed});function ih({isSelecting:e,selectionKeyPressed:t,selectionMode:n=xt.Full,panOnDrag:o,autoPanOnSelection:r,paneClickDistance:i,selectionOnDrag:s,onSelectionStart:a,onSelectionEnd:u,onPaneClick:c,onPaneContextMenu:l,onPaneScroll:f,onPaneMouseEnter:d,onPaneMouseMove:h,onPaneMouseLeave:g,children:_}){const w=D.useRef(0),y=oe(),{userSelectionActive:C,elementsSelectable:p,dragging:v,panBy:A,autoPanSpeed:S}=te(rh,ie),b=p&&(e||C),T=D.useRef(null),k=D.useRef(),F=D.useRef(new Set),z=D.useRef(new Set),B=D.useRef(!1),O=D.useRef(!1),x=D.useRef({x:0,y:0}),M=D.useRef(!1),N=H=>{if(O.current||B.current||y.getState().connection.inProgress){O.current=!1,B.current=!1;return}c?.(H),y.getState().resetSelectedElements(),y.setState({nodesSelectionActive:!1})},I=H=>{if(Array.isArray(o)&&o?.includes(2)){H.preventDefault();return}l?.(H)},$=f?H=>f(H):void 0,P=H=>{O.current&&(H.stopPropagation(),O.current=!1)},j=H=>{const{domNode:X,transform:J}=y.getState();if(k.current=X?.getBoundingClientRect(),!k.current)return;const Q=H.target===T.current;if(!Q&&!!H.target.closest(".nokey")||!e||!(s&&Q||t)||H.button!==0||!H.isPrimary)return;H.target?.setPointerCapture?.(H.pointerId),O.current=!1;const{x:ee,y:ne}=me(H.nativeEvent,k.current),re=Mt({x:ee,y:ne},J);y.setState({userSelectionRect:{width:0,height:0,startX:re.x,startY:re.y,x:ee,y:ne}}),Q||(H.stopPropagation(),H.preventDefault())};function m(H,X){const{userSelectionRect:J}=y.getState();if(!J)return;const{transform:Q,nodeLookup:q,edgeLookup:U,connectionLookup:ee,triggerNodeChanges:ne,triggerEdgeChanges:re,defaultEdgeOptions:ce}=y.getState(),Ce={x:J.startX,y:J.startY},{x:we,y:ve}=ot(Ce,Q),Ne={startX:Ce.x,startY:Ce.y,x:Hde.id)),z.current=new Set;const ze=ce?.selectable??!0;for(const de of F.current){const Me=ee.get(de);if(Me)for(const{edgeId:Ae}of Me.values()){const Oe=U.get(Ae);Oe&&(Oe.selectable??ze)&&z.current.add(Ae)}}if(!Wo(it,F.current)){const de=Ue(q,F.current,!0);ne(de)}if(!Wo(He,z.current)){const de=Ue(U,z.current);re(de)}y.setState({userSelectionRect:Ne,userSelectionActive:!0,nodesSelectionActive:!1})}function E(){if(!r||!k.current)return;const[H,X]=no(x.current,k.current,S);A({x:H,y:X}).then(J=>{if(!O.current||!J){w.current=requestAnimationFrame(E);return}const{x:Q,y:q}=x.current;m(Q,q),w.current=requestAnimationFrame(E)})}const V=()=>{cancelAnimationFrame(w.current),w.current=0,M.current=!1};D.useEffect(()=>()=>V(),[]);const L=H=>{const{userSelectionRect:X,transform:J,resetSelectedElements:Q}=y.getState();if(!k.current||!X)return;const{x:q,y:U}=me(H.nativeEvent,k.current);x.current={x:q,y:U};const ee=ot({x:X.startX,y:X.startY},J);if(!O.current){const ne=t?0:i;if(Math.hypot(q-ee.x,U-ee.y)<=ne)return;Q(),a?.(H)}O.current=!0,M.current||(E(),M.current=!0),m(q,U)},Y=H=>{if(!b){H.target===T.current&&y.getState().connection.inProgress&&(B.current=!0);return}H.button===0&&(H.target?.releasePointerCapture?.(H.pointerId),!C&&H.target===T.current&&y.getState().userSelectionRect&&N?.(H),y.setState({userSelectionActive:!1,userSelectionRect:null}),O.current&&(u?.(H),y.setState({nodesSelectionActive:F.current.size>0})),V())},W=H=>{H.target?.releasePointerCapture?.(H.pointerId),V()},Z=o===!0||Array.isArray(o)&&o.includes(0);return R.jsxs("div",{className:se(["react-flow__pane",{draggable:Z,dragging:v,selection:e}]),onClick:b?void 0:kn(N,T),onContextMenu:kn(I,T),onWheel:kn($,T),onPointerEnter:b?void 0:d,onPointerMove:b?L:h,onPointerUp:Y,onPointerCancel:b?W:void 0,onPointerDownCapture:b?j:void 0,onClickCapture:b?P:void 0,onPointerLeave:g,ref:T,style:dn,children:[_,R.jsx(oh,{})]})}function Zn({id:e,store:t,unselect:n=!1,nodeRef:o}){const{addSelectedNodes:r,unselectNodesAndEdges:i,multiSelectionActive:s,nodeLookup:a,onError:u}=t.getState(),c=a.get(e);if(!c){u?.("012",ye.error012(e));return}t.setState({nodesSelectionActive:!1}),c.selected?(n||c.selected&&s)&&(i({nodes:[c],edges:[]}),requestAnimationFrame(()=>o?.current?.blur())):r([e])}function Qi({nodeRef:e,disabled:t=!1,noDragClassName:n,handleSelector:o,nodeId:r,isSelectable:i,nodeClickDistance:s}){const a=oe(),[u,c]=D.useState(!1),l=D.useRef();return D.useEffect(()=>{if(!t)return l.current=Yf({getStoreItems:()=>a.getState(),onNodeMouseDown:f=>{Zn({id:f,store:a,nodeRef:e})},onDragStart:()=>{c(!0)},onDragStop:()=>{c(!1)}}),()=>{l.current?.destroy(),l.current=void 0}},[t,a,e]),D.useEffect(()=>{t||!e.current||!l.current||l.current.update({noDragClassName:n,handleSelector:o,domNode:e.current,isSelectable:i,nodeId:r,nodeClickDistance:s})},[n,o,t,i,e,r,s]),u}const sh=e=>t=>t.selected&&(t.draggable||e&&typeof t.draggable>"u");function Ji(){const e=oe();return D.useCallback(n=>{const{nodeExtent:o,snapToGrid:r,snapGrid:i,nodesDraggable:s,onError:a,updateNodePositions:u,nodeLookup:c,nodeOrigin:l}=e.getState(),f=new Map,d=sh(s),h=r?i[0]:5,g=r?i[1]:5,_=n.direction.x*h*n.factor,w=n.direction.y*g*n.factor;for(const[,y]of c){if(!d(y))continue;let C={x:y.internals.positionAbsolute.x+_,y:y.internals.positionAbsolute.y+w};r&&(C=Nt(C,i));const{position:p,positionAbsolute:v}=xi({nodeId:y.id,nextPosition:C,nodeLookup:c,nodeExtent:o,nodeOrigin:l,onError:a});y.position=p,y.internals.positionAbsolute=v,f.set(y.id,y)}u(f)},[])}const fo=D.createContext(null),ah=fo.Provider;fo.Consumer;const es=()=>D.useContext(fo),ch=e=>({connectOnClick:e.connectOnClick,noPanClassName:e.noPanClassName,rfId:e.rfId}),ts=D.createContext(null);function uh({children:e}){const t=te(ch,ie);return R.jsx(ts.Provider,{value:t,children:e})}function lh(){const e=D.useContext(ts);if(!e)throw new Error("useHandleConfig must be used within a HandleConfigProvider");return e}const fh={connectingFrom:!1,connectingTo:!1,clickConnecting:!1,isPossibleEndHandle:!0,connectionInProcess:!1,clickConnectionInProcess:!1,valid:!1},dh=(e,t,n)=>o=>{const{connectionClickStartHandle:r,connectionMode:i,connection:s}=o,{fromHandle:a,toHandle:u,isValid:c}=s;if(!a&&!r)return fh;const l=u?.nodeId===e&&u?.id===t&&u?.type===n;return{connectingFrom:a?.nodeId===e&&a?.id===t&&a?.type===n,connectingTo:l,clickConnecting:r?.nodeId===e&&r?.id===t&&r?.type===n,isPossibleEndHandle:i===tt.Strict?a?.type!==n:e!==a?.nodeId||t!==a?.id,connectionInProcess:!!a,clickConnectionInProcess:!!r,valid:l&&c}};function hh({type:e="source",position:t=G.Top,isValidConnection:n,isConnectable:o=!0,isConnectableStart:r=!0,isConnectableEnd:i=!0,id:s,onConnect:a,children:u,className:c,onMouseDown:l,onTouchStart:f,...d},h){const g=s||null,_=e==="target",w=oe(),y=es(),{connectOnClick:C,noPanClassName:p,rfId:v}=lh(),{connectingFrom:A,connectingTo:S,clickConnecting:b,isPossibleEndHandle:T,connectionInProcess:k,clickConnectionInProcess:F,valid:z}=te(dh(y,g,e),ie);y||w.getState().onError?.("010",ye.error010());const B=M=>{const{defaultEdgeOptions:N,onConnect:I,hasDefaultEdges:$}=w.getState(),P={...N,...M};if($){const{edges:j,setEdges:m,onError:E}=w.getState();m(Xd(P,j,{onError:E}))}I?.(P),a?.(P)},O=M=>{if(!y)return;const N=Mi(M.nativeEvent);if(r&&(N&&M.button===0||!N)){const I=w.getState();Xn.onPointerDown(M.nativeEvent,{handleDomNode:M.currentTarget,autoPanOnConnect:I.autoPanOnConnect,connectionMode:I.connectionMode,connectionRadius:I.connectionRadius,domNode:I.domNode,nodeLookup:I.nodeLookup,lib:I.lib,isTarget:_,handleId:g,nodeId:y,flowId:I.rfId,panBy:I.panBy,cancelConnection:I.cancelConnection,onConnectStart:I.onConnectStart,onConnectEnd:(...$)=>w.getState().onConnectEnd?.(...$),updateConnection:I.updateConnection,onConnect:B,isValidConnection:n||((...$)=>w.getState().isValidConnection?.(...$)??!0),getTransform:()=>w.getState().transform,getFromHandle:()=>w.getState().connection.fromHandle,autoPanSpeed:I.autoPanSpeed,dragThreshold:I.connectionDragThreshold})}N?l?.(M):f?.(M)},x=M=>{const{onClickConnectStart:N,onClickConnectEnd:I,connectionClickStartHandle:$,connectionMode:P,isValidConnection:j,lib:m,rfId:E,nodeLookup:V,connection:L}=w.getState();if(!y||!$&&!r)return;if(!$){N?.(M.nativeEvent,{nodeId:y,handleId:g,handleType:e}),w.setState({connectionClickStartHandle:{nodeId:y,type:e,id:g}});return}const Y=Ci(M.target),W=n||j,{connection:Z,isValid:H}=Xn.isValid(M.nativeEvent,{handle:{nodeId:y,id:g,type:e},connectionMode:P,fromNodeId:$.nodeId,fromHandleId:$.id||null,fromType:$.type,isValidConnection:W,flowId:E,doc:Y,lib:m,nodeLookup:V});H&&Z&&B(Z);const X=structuredClone(L);delete X.inProgress,X.toPosition=X.toHandle?X.toHandle.position:null,I?.(M,X),w.setState({connectionClickStartHandle:null})};return R.jsx("div",{"data-handleid":g,"data-nodeid":y,"data-handlepos":t,"data-id":`${v}-${y}-${g}-${e}`,className:se(["react-flow__handle",`react-flow__handle-${t}`,"nodrag",p,c,{source:!_,target:_,connectable:o,connectablestart:r,connectableend:i,clickconnecting:b,connectingfrom:A,connectingto:S,valid:z,connectionindicator:o&&(!k||T)&&(k||F?i:r)}]),onMouseDown:O,onTouchStart:O,onClick:C?x:void 0,ref:h,...d,children:u})}const Qt=D.memo(Gi(hh));function gh({data:e,isConnectable:t,sourcePosition:n=G.Bottom}){return R.jsxs(R.Fragment,{children:[e?.label,R.jsx(Qt,{type:"source",position:n,isConnectable:t})]})}function ph({data:e,isConnectable:t,targetPosition:n=G.Top,sourcePosition:o=G.Bottom}){return R.jsxs(R.Fragment,{children:[R.jsx(Qt,{type:"target",position:n,isConnectable:t}),e?.label,R.jsx(Qt,{type:"source",position:o,isConnectable:t})]})}function mh(){return null}function yh({data:e,isConnectable:t,targetPosition:n=G.Top}){return R.jsxs(R.Fragment,{children:[R.jsx(Qt,{type:"target",position:n,isConnectable:t}),e?.label]})}const Jt={ArrowUp:{x:0,y:-1},ArrowDown:{x:0,y:1},ArrowLeft:{x:-1,y:0},ArrowRight:{x:1,y:0}},Sr={input:gh,default:ph,output:yh,group:mh};function xh(e){return e.internals.handleBounds===void 0?{width:e.width??e.initialWidth??e.style?.width,height:e.height??e.initialHeight??e.style?.height}:{width:e.width??e.style?.width,height:e.height??e.style?.height}}const wh=e=>{const{width:t,height:n,x:o,y:r}=Ct(e.nodeLookup,{filter:i=>!!i.selected});return{width:pe(t)?t:null,height:pe(n)?n:null,userSelectionActive:e.userSelectionActive,transformString:`translate(${e.transform[0]}px,${e.transform[1]}px) scale(${e.transform[2]}) translate(${o}px,${r}px)`}};function vh({onSelectionContextMenu:e,noPanClassName:t,disableKeyboardA11y:n}){const o=oe(),{width:r,height:i,transformString:s,userSelectionActive:a}=te(wh,ie),u=Ji(),c=D.useRef(null);D.useEffect(()=>{n||c.current?.focus({preventScroll:!0})},[n]);const l=!a&&r!==null&&i!==null;if(Qi({nodeRef:c,disabled:!l}),!l)return null;const f=e?h=>{const g=o.getState().nodes.filter(_=>_.selected);e(h,g)}:void 0,d=h=>{Object.prototype.hasOwnProperty.call(Jt,h.key)&&(h.preventDefault(),u({direction:Jt[h.key],factor:h.shiftKey?4:1}))};return R.jsx("div",{className:se(["react-flow__nodesselection","react-flow__container",t]),style:{transform:s},children:R.jsx("div",{ref:c,className:"react-flow__nodesselection-rect",onContextMenu:f,tabIndex:n?void 0:-1,onKeyDown:n?void 0:d,style:{width:r,height:i}})})}const Cr=typeof window<"u"?window:void 0,_h=e=>({nodesSelectionActive:e.nodesSelectionActive,userSelectionActive:e.userSelectionActive});function ns({children:e,onPaneClick:t,onPaneMouseEnter:n,onPaneMouseMove:o,onPaneMouseLeave:r,onPaneContextMenu:i,onPaneScroll:s,paneClickDistance:a,deleteKeyCode:u,selectionKeyCode:c,selectionOnDrag:l,selectionMode:f,onSelectionStart:d,onSelectionEnd:h,multiSelectionKeyCode:g,panActivationKeyCode:_,zoomActivationKeyCode:w,elementsSelectable:y,zoomOnScroll:C,zoomOnPinch:p,panOnScroll:v,panOnScrollSpeed:A,panOnScrollMode:S,zoomOnDoubleClick:b,panOnDrag:T,autoPanOnSelection:k,defaultViewport:F,translateExtent:z,minZoom:B,maxZoom:O,preventScrolling:x,onSelectionContextMenu:M,noWheelClassName:N,noPanClassName:I,disableKeyboardA11y:$,onViewportChange:P,isControlledViewport:j}){const{nodesSelectionActive:m,userSelectionActive:E}=te(_h,ie),V=_t(c,{target:Cr}),L=_t(_,{target:Cr}),Y=L||T,W=L||v,Z=l&&Y!==!0,H=V||E||Z;return Qd({deleteKeyCode:u,multiSelectionKeyCode:g}),R.jsx(th,{onPaneContextMenu:i,elementsSelectable:y,zoomOnScroll:C,zoomOnPinch:p,panOnScroll:W,panOnScrollSpeed:A,panOnScrollMode:S,zoomOnDoubleClick:b,panOnDrag:!V&&Y,defaultViewport:F,translateExtent:z,minZoom:B,maxZoom:O,zoomActivationKeyCode:w,preventScrolling:x,noWheelClassName:N,noPanClassName:I,onViewportChange:P,isControlledViewport:j,paneClickDistance:a,selectionOnDrag:Z,children:R.jsxs(ih,{onSelectionStart:d,onSelectionEnd:h,onPaneClick:t,onPaneMouseEnter:n,onPaneMouseMove:o,onPaneMouseLeave:r,onPaneContextMenu:i,onPaneScroll:s,panOnDrag:Y,autoPanOnSelection:k,isSelecting:!!H,selectionMode:f,selectionKeyPressed:V,paneClickDistance:a,selectionOnDrag:Z,children:[e,m&&R.jsx(vh,{onSelectionContextMenu:M,noPanClassName:I,disableKeyboardA11y:$})]})})}ns.displayName="FlowRenderer";const Eh=D.memo(ns),bh=e=>t=>e?to(t.nodeLookup,{x:0,y:0,width:t.width,height:t.height},t.transform,!0).map(n=>n.id):Array.from(t.nodeLookup.keys());function Sh(e){return te(D.useCallback(bh(e),[e]),ie)}const Ch=e=>e.updateNodeInternals;function Nh(){const e=te(Ch),[t]=D.useState(()=>typeof ResizeObserver>"u"?null:new ResizeObserver(n=>{const o=new Map;n.forEach(r=>{const i=r.target.getAttribute("data-id");o.set(i,{id:i,nodeElement:r.target,force:!0})}),e(o)}));return D.useEffect(()=>()=>{t?.disconnect()},[t]),t}function Mh({node:e,nodeType:t,hasDimensions:n,resizeObserver:o}){const r=oe(),i=D.useRef(null),s=D.useRef(null),a=D.useRef(e.sourcePosition),u=D.useRef(e.targetPosition),c=D.useRef(t),l=n&&!!e.internals.handleBounds;return D.useEffect(()=>{i.current&&!e.hidden&&(!l||s.current!==i.current)&&(s.current&&o?.unobserve(s.current),o?.observe(i.current),s.current=i.current)},[l,e.hidden]),D.useEffect(()=>()=>{s.current&&(o?.unobserve(s.current),s.current=null)},[]),D.useEffect(()=>{if(i.current){const f=c.current!==t,d=a.current!==e.sourcePosition,h=u.current!==e.targetPosition;(f||d||h)&&(c.current=t,a.current=e.sourcePosition,u.current=e.targetPosition,r.getState().updateNodeInternals(new Map([[e.id,{id:e.id,nodeElement:i.current,force:!0}]])))}},[e.id,t,e.sourcePosition,e.targetPosition]),i}function Ah({id:e,onClick:t,onMouseEnter:n,onMouseMove:o,onMouseLeave:r,onContextMenu:i,onDoubleClick:s,nodesDraggable:a,elementsSelectable:u,nodesConnectable:c,nodesFocusable:l,resizeObserver:f,noDragClassName:d,noPanClassName:h,disableKeyboardA11y:g,rfId:_,nodeTypes:w,nodeClickDistance:y,onError:C}){const{node:p,internals:v,isParent:A}=te(H=>{const X=H.nodeLookup.get(e),J=H.parentLookup.has(e);return{node:X,internals:X.internals,isParent:J}},ie);let S=p.type||"default",b=w?.[S]||Sr[S];b===void 0&&(C?.("003",ye.error003(S)),S="default",b=w?.default||Sr.default);const T=!!(p.draggable||a&&typeof p.draggable>"u"),k=!!(p.selectable||u&&typeof p.selectable>"u"),F=!!(p.connectable||c&&typeof p.connectable>"u"),z=!!(p.focusable||l&&typeof p.focusable>"u"),B=oe(),O=bi(p),x=Mh({node:p,nodeType:S,hasDimensions:O,resizeObserver:f}),M=Qi({nodeRef:x,disabled:p.hidden||!T,noDragClassName:d,handleSelector:p.dragHandle,nodeId:e,isSelectable:k,nodeClickDistance:y}),N=Ji();if(p.hidden)return null;const I=Se(p),$=xh(p),P=k||T||t||n||o||r,j=n?H=>n(H,{...v.userNode}):void 0,m=o?H=>o(H,{...v.userNode}):void 0,E=r?H=>r(H,{...v.userNode}):void 0,V=i?H=>i(H,{...v.userNode}):void 0,L=s?H=>s(H,{...v.userNode}):void 0,Y=H=>{const{selectNodesOnDrag:X,nodeDragThreshold:J}=B.getState();k&&(!X||!T||J>0)&&Zn({id:e,store:B,nodeRef:x}),t&&t(H,{...v.userNode})},W=H=>{if(!(Ni(H.nativeEvent)||g)){if(hi.includes(H.key)&&k){const X=H.key==="Escape";Zn({id:e,store:B,unselect:X,nodeRef:x})}else if(T&&p.selected&&Object.prototype.hasOwnProperty.call(Jt,H.key)){H.preventDefault();const{ariaLabelConfig:X}=B.getState();B.setState({ariaLiveMessage:X["node.a11yDescription.ariaLiveMessage"]({direction:H.key.replace("Arrow","").toLowerCase(),x:~~v.positionAbsolute.x,y:~~v.positionAbsolute.y})}),N({direction:Jt[H.key],factor:H.shiftKey?4:1})}}},Z=()=>{if(g||!x.current?.matches(":focus-visible"))return;const{transform:H,width:X,height:J,autoPanOnNodeFocus:Q,setCenter:q}=B.getState();if(!Q)return;to(new Map([[e,p]]),{x:0,y:0,width:X,height:J},H,!0).length>0||q(p.position.x+I.width/2,p.position.y+I.height/2,{zoom:H[2]})};return R.jsx("div",{className:se(["react-flow__node",`react-flow__node-${S}`,{[h]:T},p.className,{selected:p.selected,selectable:k,parent:A,draggable:T,dragging:M}]),ref:x,style:{zIndex:v.z,transform:`translate(${v.positionAbsolute.x}px,${v.positionAbsolute.y}px)`,pointerEvents:P?"all":"none",visibility:O?"visible":"hidden",...p.style,...$},"data-id":e,"data-testid":`rf__node-${e}`,onMouseEnter:j,onMouseMove:m,onMouseLeave:E,onContextMenu:V,onClick:Y,onDoubleClick:L,onKeyDown:z?W:void 0,tabIndex:z?0:void 0,onFocus:z?Z:void 0,role:p.ariaRole??(z?"group":void 0),"aria-roledescription":"node","aria-describedby":g?void 0:`${Xi}-${_}`,"aria-label":p.ariaLabel,...p.domAttributes,children:R.jsx(ah,{value:e,children:R.jsx(b,{id:e,data:p.data,type:S,positionAbsoluteX:v.positionAbsolute.x,positionAbsoluteY:v.positionAbsolute.y,selected:p.selected??!1,selectable:k,draggable:T,deletable:p.deletable??!0,isConnectable:F,sourcePosition:p.sourcePosition,targetPosition:p.targetPosition,dragging:M,dragHandle:p.dragHandle,zIndex:v.z,parentId:p.parentId,...I})})})}var Ih=D.memo(Ah);const Th=e=>({nodesConnectable:e.nodesConnectable,nodesFocusable:e.nodesFocusable,elementsSelectable:e.elementsSelectable,onError:e.onError});function os(e){const{nodesConnectable:t,nodesFocusable:n,elementsSelectable:o,onError:r}=te(Th,ie),i=Sh(e.onlyRenderVisibleElements),s=Nh();return R.jsx("div",{className:"react-flow__nodes",style:dn,children:i.map(a=>R.jsx(Ih,{id:a,nodeTypes:e.nodeTypes,nodeExtent:e.nodeExtent,onClick:e.onNodeClick,onMouseEnter:e.onNodeMouseEnter,onMouseMove:e.onNodeMouseMove,onMouseLeave:e.onNodeMouseLeave,onContextMenu:e.onNodeContextMenu,onDoubleClick:e.onNodeDoubleClick,noDragClassName:e.noDragClassName,noPanClassName:e.noPanClassName,rfId:e.rfId,disableKeyboardA11y:e.disableKeyboardA11y,resizeObserver:s,nodesDraggable:e.nodesDraggable??!0,nodesConnectable:t,nodesFocusable:n,elementsSelectable:o,nodeClickDistance:e.nodeClickDistance,onError:r},a))})}os.displayName="NodeRenderer";const kh=D.memo(os);function Rh(e){return te(D.useCallback(n=>{if(!e)return n.edges.map(r=>r.id);const o=[];if(n.width&&n.height)for(const r of n.edges){const i=n.nodeLookup.get(r.source),s=n.nodeLookup.get(r.target);i&&s&&Cf({sourceNode:i,targetNode:s,width:n.width,height:n.height,transform:n.transform})&&o.push(r.id)}return o},[e]),ie)}const Ph=({color:e="none",strokeWidth:t=1})=>{const n={strokeWidth:t,...e&&{stroke:e}};return R.jsx("polyline",{className:"arrow",style:n,strokeLinecap:"round",fill:"none",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4"})},$h=({color:e="none",strokeWidth:t=1})=>{const n={strokeWidth:t,...e&&{stroke:e,fill:e}};return R.jsx("polyline",{className:"arrowclosed",style:n,strokeLinecap:"round",strokeLinejoin:"round",points:"-5,-4 0,0 -5,4 -5,-4"})},Nr={[Gt.Arrow]:Ph,[Gt.ArrowClosed]:$h};function Dh(e){const t=oe();return D.useMemo(()=>Object.prototype.hasOwnProperty.call(Nr,e)?Nr[e]:(t.getState().onError?.("009",ye.error009(e)),null),[e])}const Hh=({id:e,type:t,color:n,width:o=12.5,height:r=12.5,markerUnits:i="strokeWidth",strokeWidth:s,orient:a="auto-start-reverse"})=>{const u=Dh(t);return u?R.jsx("marker",{className:"react-flow__arrowhead",id:e,markerWidth:`${o}`,markerHeight:`${r}`,viewBox:"-10 -10 20 20",markerUnits:i,orient:a,refX:"0",refY:"0",children:R.jsx(u,{color:n,strokeWidth:s})}):null},rs=({defaultColor:e,rfId:t})=>{const n=te(i=>i.edges),o=te(i=>i.defaultEdgeOptions),r=D.useMemo(()=>Pf(n,{id:t,defaultColor:e,defaultMarkerStart:o?.markerStart,defaultMarkerEnd:o?.markerEnd}),[n,o,t,e]);return r.length?R.jsx("svg",{className:"react-flow__marker","aria-hidden":"true",children:R.jsx("defs",{children:r.map(i=>R.jsx(Hh,{id:i.id,type:i.type,color:i.color,width:i.width,height:i.height,markerUnits:i.markerUnits,strokeWidth:i.strokeWidth,orient:i.orient},i.id))})}):null};rs.displayName="MarkerDefinitions";var zh=D.memo(rs);function is({x:e,y:t,label:n,labelStyle:o,labelShowBg:r=!0,labelBgStyle:i,labelBgPadding:s=[2,4],labelBgBorderRadius:a=2,children:u,className:c,...l}){const[f,d]=D.useState({x:1,y:0,width:0,height:0}),h=se(["react-flow__edge-textwrapper",c]),g=D.useRef(null);return D.useEffect(()=>{if(g.current){const _=g.current.getBBox();d({x:_.x,y:_.y,width:_.width,height:_.height})}},[n]),n?R.jsxs("g",{transform:`translate(${e-f.width/2} ${t-f.height/2})`,className:h,visibility:f.width?"visible":"hidden",...l,children:[r&&R.jsx("rect",{width:f.width+2*s[0],x:-s[0],y:-s[1],height:f.height+2*s[1],className:"react-flow__edge-textbg",style:i,rx:a,ry:a}),R.jsx("text",{className:"react-flow__edge-text",y:f.height/2,dy:"0.3em",ref:g,style:o,children:n}),u]}):null}is.displayName="EdgeText";const Oh=D.memo(is);function hn({path:e,labelX:t,labelY:n,label:o,labelStyle:r,labelShowBg:i,labelBgStyle:s,labelBgPadding:a,labelBgBorderRadius:u,interactionWidth:c=20,...l}){return R.jsxs(R.Fragment,{children:[R.jsx("path",{...l,d:e,fill:"none",className:se(["react-flow__edge-path",l.className])}),c?R.jsx("path",{d:e,fill:"none",strokeOpacity:0,strokeWidth:c,className:"react-flow__edge-interaction"}):null,o&&pe(t)&&pe(n)?R.jsx(Oh,{x:t,y:n,label:o,labelStyle:r,labelShowBg:i,labelBgStyle:s,labelBgPadding:a,labelBgBorderRadius:u}):null]})}function Mr({pos:e,x1:t,y1:n,x2:o,y2:r}){return e===G.Left||e===G.Right?[.5*(t+o),n]:[t,.5*(n+r)]}function ss({sourceX:e,sourceY:t,sourcePosition:n=G.Bottom,targetX:o,targetY:r,targetPosition:i=G.Top}){const[s,a]=Mr({pos:n,x1:e,y1:t,x2:o,y2:r}),[u,c]=Mr({pos:i,x1:o,y1:r,x2:e,y2:t}),[l,f,d,h]=Ai({sourceX:e,sourceY:t,targetX:o,targetY:r,sourceControlX:s,sourceControlY:a,targetControlX:u,targetControlY:c});return[`M${e},${t} C${s},${a} ${u},${c} ${o},${r}`,l,f,d,h]}function as(e){return D.memo(({id:t,sourceX:n,sourceY:o,targetX:r,targetY:i,sourcePosition:s,targetPosition:a,label:u,labelStyle:c,labelShowBg:l,labelBgStyle:f,labelBgPadding:d,labelBgBorderRadius:h,style:g,markerEnd:_,markerStart:w,interactionWidth:y})=>{const[C,p,v]=ss({sourceX:n,sourceY:o,sourcePosition:s,targetX:r,targetY:i,targetPosition:a}),A=e.isInternal?void 0:t;return R.jsx(hn,{id:A,path:C,labelX:p,labelY:v,label:u,labelStyle:c,labelShowBg:l,labelBgStyle:f,labelBgPadding:d,labelBgBorderRadius:h,style:g,markerEnd:_,markerStart:w,interactionWidth:y})})}const Lh=as({isInternal:!1}),cs=as({isInternal:!0});Lh.displayName="SimpleBezierEdge";cs.displayName="SimpleBezierEdgeInternal";function us(e){return D.memo(({id:t,sourceX:n,sourceY:o,targetX:r,targetY:i,label:s,labelStyle:a,labelShowBg:u,labelBgStyle:c,labelBgPadding:l,labelBgBorderRadius:f,style:d,sourcePosition:h=G.Bottom,targetPosition:g=G.Top,markerEnd:_,markerStart:w,pathOptions:y,interactionWidth:C})=>{const[p,v,A]=jn({sourceX:n,sourceY:o,sourcePosition:h,targetX:r,targetY:i,targetPosition:g,borderRadius:y?.borderRadius,offset:y?.offset,stepPosition:y?.stepPosition}),S=e.isInternal?void 0:t;return R.jsx(hn,{id:S,path:p,labelX:v,labelY:A,label:s,labelStyle:a,labelShowBg:u,labelBgStyle:c,labelBgPadding:l,labelBgBorderRadius:f,style:d,markerEnd:_,markerStart:w,interactionWidth:C})})}const ls=us({isInternal:!1}),fs=us({isInternal:!0});ls.displayName="SmoothStepEdge";fs.displayName="SmoothStepEdgeInternal";function ds(e){return D.memo(({id:t,...n})=>{const o=e.isInternal?void 0:t;return R.jsx(ls,{...n,id:o,pathOptions:D.useMemo(()=>({borderRadius:0,offset:n.pathOptions?.offset}),[n.pathOptions?.offset])})})}const Vh=ds({isInternal:!1}),hs=ds({isInternal:!0});Vh.displayName="StepEdge";hs.displayName="StepEdgeInternal";function gs(e){return D.memo(({id:t,sourceX:n,sourceY:o,targetX:r,targetY:i,label:s,labelStyle:a,labelShowBg:u,labelBgStyle:c,labelBgPadding:l,labelBgBorderRadius:f,style:d,markerEnd:h,markerStart:g,interactionWidth:_})=>{const[w,y,C]=ki({sourceX:n,sourceY:o,targetX:r,targetY:i}),p=e.isInternal?void 0:t;return R.jsx(hn,{id:p,path:w,labelX:y,labelY:C,label:s,labelStyle:a,labelShowBg:u,labelBgStyle:c,labelBgPadding:l,labelBgBorderRadius:f,style:d,markerEnd:h,markerStart:g,interactionWidth:_})})}const Bh=gs({isInternal:!1}),ps=gs({isInternal:!0});Bh.displayName="StraightEdge";ps.displayName="StraightEdgeInternal";function ms(e){return D.memo(({id:t,sourceX:n,sourceY:o,targetX:r,targetY:i,sourcePosition:s=G.Bottom,targetPosition:a=G.Top,label:u,labelStyle:c,labelShowBg:l,labelBgStyle:f,labelBgPadding:d,labelBgBorderRadius:h,style:g,markerEnd:_,markerStart:w,pathOptions:y,interactionWidth:C})=>{const[p,v,A]=Ii({sourceX:n,sourceY:o,sourcePosition:s,targetX:r,targetY:i,targetPosition:a,curvature:y?.curvature}),S=e.isInternal?void 0:t;return R.jsx(hn,{id:S,path:p,labelX:v,labelY:A,label:u,labelStyle:c,labelShowBg:l,labelBgStyle:f,labelBgPadding:d,labelBgBorderRadius:h,style:g,markerEnd:_,markerStart:w,interactionWidth:C})})}const jh=ms({isInternal:!1}),ys=ms({isInternal:!0});jh.displayName="BezierEdge";ys.displayName="BezierEdgeInternal";const Ar={default:ys,straight:ps,step:hs,smoothstep:fs,simplebezier:cs},Ir={sourceX:null,sourceY:null,targetX:null,targetY:null,sourcePosition:null,targetPosition:null,zIndex:void 0},Fh=(e,t,n)=>n===G.Left?e-t:n===G.Right?e+t:e,Yh=(e,t,n)=>n===G.Top?e-t:n===G.Bottom?e+t:e,Tr="react-flow__edgeupdater";function kr({position:e,centerX:t,centerY:n,radius:o=10,onMouseDown:r,onMouseEnter:i,onMouseOut:s,type:a}){return R.jsx("circle",{onMouseDown:r,onMouseEnter:i,onMouseOut:s,className:se([Tr,`${Tr}-${a}`]),cx:Fh(t,o,e),cy:Yh(n,o,e),r:o,stroke:"transparent",fill:"transparent"})}function Xh({isReconnectable:e,reconnectRadius:t,edge:n,sourceX:o,sourceY:r,targetX:i,targetY:s,sourcePosition:a,targetPosition:u,onReconnect:c,onReconnectStart:l,onReconnectEnd:f,setReconnecting:d,setUpdateHover:h}){const g=oe(),_=(v,A)=>{if(v.button!==0)return;const{autoPanOnConnect:S,domNode:b,connectionMode:T,connectionRadius:k,lib:F,onConnectStart:z,cancelConnection:B,nodeLookup:O,rfId:x,panBy:M,updateConnection:N}=g.getState(),I=A.type==="target",$=(m,E)=>{d(!1),f?.(m,n,A.type,E)},P=m=>c?.(n,m),j=(m,E)=>{d(!0),l?.(v,n,A.type),z?.(m,E)};Xn.onPointerDown(v.nativeEvent,{autoPanOnConnect:S,connectionMode:T,connectionRadius:k,domNode:b,handleId:A.id,nodeId:A.nodeId,nodeLookup:O,isTarget:I,edgeUpdaterType:A.type,lib:F,flowId:x,cancelConnection:B,panBy:M,isValidConnection:(...m)=>g.getState().isValidConnection?.(...m)??!0,onConnect:P,onConnectStart:j,onConnectEnd:(...m)=>g.getState().onConnectEnd?.(...m),onReconnectEnd:$,updateConnection:N,getTransform:()=>g.getState().transform,getFromHandle:()=>g.getState().connection.fromHandle,dragThreshold:g.getState().connectionDragThreshold,handleDomNode:v.currentTarget})},w=v=>_(v,{nodeId:n.target,id:n.targetHandle??null,type:"target"}),y=v=>_(v,{nodeId:n.source,id:n.sourceHandle??null,type:"source"}),C=()=>h(!0),p=()=>h(!1);return R.jsxs(R.Fragment,{children:[(e===!0||e==="source")&&R.jsx(kr,{position:a,centerX:o,centerY:r,radius:t,onMouseDown:w,onMouseEnter:C,onMouseOut:p,type:"source"}),(e===!0||e==="target")&&R.jsx(kr,{position:u,centerX:i,centerY:s,radius:t,onMouseDown:y,onMouseEnter:C,onMouseOut:p,type:"target"})]})}function Zh({id:e,edgesFocusable:t,edgesReconnectable:n,elementsSelectable:o,onClick:r,onDoubleClick:i,onContextMenu:s,onMouseEnter:a,onMouseMove:u,onMouseLeave:c,reconnectRadius:l,onReconnect:f,onReconnectStart:d,onReconnectEnd:h,rfId:g,edgeTypes:_,noPanClassName:w,onError:y,disableKeyboardA11y:C}){let p=te(q=>q.edgeLookup.get(e));const v=te(q=>q.defaultEdgeOptions);p=v?{...v,...p}:p;let A=p.type||"default",S=_?.[A]||Ar[A];S===void 0&&(y?.("011",ye.error011(A)),A="default",S=_?.default||Ar.default);const b=!!(p.focusable||t&&typeof p.focusable>"u"),T=typeof f<"u"&&(p.reconnectable||n&&typeof p.reconnectable>"u"),k=!!(p.selectable||o&&typeof p.selectable>"u"),F=D.useRef(null),[z,B]=D.useState(!1),[O,x]=D.useState(!1),M=oe(),{zIndex:N=p.zIndex,sourceX:I,sourceY:$,targetX:P,targetY:j,sourcePosition:m,targetPosition:E}=te(D.useCallback(q=>{const U=q.nodeLookup.get(p.source),ee=q.nodeLookup.get(p.target);if(!U||!ee)return Ir;const ne=Rf({id:e,sourceNode:U,targetNode:ee,sourceHandle:p.sourceHandle||null,targetHandle:p.targetHandle||null,connectionMode:q.connectionMode,onError:y}),re=Sf({selected:p.selected,zIndex:p.zIndex,sourceNode:U,targetNode:ee,elevateOnSelect:q.elevateEdgesOnSelect,zIndexMode:q.zIndexMode});return{...ne||Ir,zIndex:re}},[p.source,p.target,p.sourceHandle,p.targetHandle,p.selected,p.zIndex]),ie),V=D.useMemo(()=>p.markerStart?`url('#${Fn(p.markerStart,g)}')`:void 0,[p.markerStart,g]),L=D.useMemo(()=>p.markerEnd?`url('#${Fn(p.markerEnd,g)}')`:void 0,[p.markerEnd,g]);if(p.hidden||I===null||$===null||P===null||j===null)return null;const Y=q=>{const{addSelectedEdges:U,unselectNodesAndEdges:ee,multiSelectionActive:ne}=M.getState();k&&(M.setState({nodesSelectionActive:!1}),p.selected&&ne?(ee({nodes:[],edges:[p]}),F.current?.blur()):U([e])),r&&r(q,p)},W=i?q=>{i(q,{...p})}:void 0,Z=s?q=>{s(q,{...p})}:void 0,H=a?q=>{a(q,{...p})}:void 0,X=u?q=>{u(q,{...p})}:void 0,J=c?q=>{c(q,{...p})}:void 0,Q=q=>{if(!C&&hi.includes(q.key)&&k){const{unselectNodesAndEdges:U,addSelectedEdges:ee}=M.getState();q.key==="Escape"?(F.current?.blur(),U({edges:[p]})):ee([e])}};return R.jsx("svg",{style:{zIndex:N},children:R.jsxs("g",{className:se(["react-flow__edge",`react-flow__edge-${A}`,p.className,w,{selected:p.selected,animated:p.animated,inactive:!k&&!r,updating:z,selectable:k}]),onClick:Y,onDoubleClick:W,onContextMenu:Z,onMouseEnter:H,onMouseMove:X,onMouseLeave:J,onKeyDown:b?Q:void 0,tabIndex:b?0:void 0,role:p.ariaRole??(b?"group":"img"),"aria-roledescription":"edge","data-id":e,"data-testid":`rf__edge-${e}`,"aria-label":p.ariaLabel===null?void 0:p.ariaLabel||`Edge from ${p.source} to ${p.target}`,"aria-describedby":b?`${Zi}-${g}`:void 0,ref:F,...p.domAttributes,children:[!O&&R.jsx(S,{id:e,source:p.source,target:p.target,type:p.type,selected:p.selected,animated:p.animated,selectable:k,deletable:p.deletable??!0,label:p.label,labelStyle:p.labelStyle,labelShowBg:p.labelShowBg,labelBgStyle:p.labelBgStyle,labelBgPadding:p.labelBgPadding,labelBgBorderRadius:p.labelBgBorderRadius,sourceX:I,sourceY:$,targetX:P,targetY:j,sourcePosition:m,targetPosition:E,data:p.data,style:p.style,sourceHandleId:p.sourceHandle,targetHandleId:p.targetHandle,markerStart:V,markerEnd:L,pathOptions:"pathOptions"in p?p.pathOptions:void 0,interactionWidth:p.interactionWidth}),T&&R.jsx(Xh,{edge:p,isReconnectable:T,reconnectRadius:l,onReconnect:f,onReconnectStart:d,onReconnectEnd:h,sourceX:I,sourceY:$,targetX:P,targetY:j,sourcePosition:m,targetPosition:E,setUpdateHover:B,setReconnecting:x})]})})}var Wh=D.memo(Zh);const qh=e=>({edgesFocusable:e.edgesFocusable,edgesReconnectable:e.edgesReconnectable,elementsSelectable:e.elementsSelectable,connectionMode:e.connectionMode,onError:e.onError});function xs({defaultMarkerColor:e,onlyRenderVisibleElements:t,rfId:n,edgeTypes:o,noPanClassName:r,onReconnect:i,onEdgeContextMenu:s,onEdgeMouseEnter:a,onEdgeMouseMove:u,onEdgeMouseLeave:c,onEdgeClick:l,reconnectRadius:f,onEdgeDoubleClick:d,onReconnectStart:h,onReconnectEnd:g,disableKeyboardA11y:_}){const{edgesFocusable:w,edgesReconnectable:y,elementsSelectable:C,onError:p}=te(qh,ie),v=Rh(t);return R.jsxs("div",{className:"react-flow__edges",children:[R.jsx(zh,{defaultColor:e,rfId:n}),v.map(A=>R.jsx(Wh,{id:A,edgesFocusable:w,edgesReconnectable:y,elementsSelectable:C,noPanClassName:r,onReconnect:i,onContextMenu:s,onMouseEnter:a,onMouseMove:u,onMouseLeave:c,onClick:l,reconnectRadius:f,onDoubleClick:d,onReconnectStart:h,onReconnectEnd:g,rfId:n,onError:p,edgeTypes:o,disableKeyboardA11y:_},A))]})}xs.displayName="EdgeRenderer";const Gh=D.memo(xs),Rr=e=>`translate(${e[0]}px,${e[1]}px) scale(${e[2]})`;function Uh({children:e}){const t=oe(),n=D.useRef(null),[o]=D.useState(()=>t.getState().transform);return Ui(()=>{let r=null;const i=()=>{const s=t.getState().transform;r&&s[0]===r[0]&&s[1]===r[1]&&s[2]===r[2]||(r=s,n.current&&(n.current.style.transform=Rr(s)))};return i(),t.subscribe(i)},[t]),R.jsx("div",{ref:n,className:"react-flow__viewport xyflow__viewport react-flow__container",style:{transform:Rr(o)},children:e})}function Kh(e){const t=lo(),n=D.useRef(!1);D.useEffect(()=>{!n.current&&t.viewportInitialized&&e&&(setTimeout(()=>e(t),1),n.current=!0)},[e,t.viewportInitialized])}const Qh=e=>e.panZoom?.syncViewport;function Jh(e){const t=te(Qh),n=oe();return D.useEffect(()=>{e&&(t?.(e),n.setState({transform:[e.x,e.y,e.zoom]}))},[e,t]),null}function eg(e){return e.connection.inProgress?{...e.connection,to:Mt(e.connection.to,e.transform)}:{...e.connection}}function tg(e){return eg}function ng(e){const t=tg();return te(t,ie)}const og=e=>({nodesConnectable:e.nodesConnectable,isValid:e.connection.isValid,inProgress:e.connection.inProgress,width:e.width,height:e.height});function rg({containerStyle:e,style:t,type:n,component:o}){const{nodesConnectable:r,width:i,height:s,isValid:a,inProgress:u}=te(og,ie);return!(i&&r&&u)?null:R.jsx("svg",{style:e,width:i,height:s,className:"react-flow__connectionline react-flow__container",children:R.jsx("g",{className:se(["react-flow__connection",mi(a)]),children:R.jsx(ws,{style:t,type:n,CustomComponent:o,isValid:a})})})}const ws=({style:e,type:t=$e.Bezier,CustomComponent:n,isValid:o})=>{const{inProgress:r,from:i,fromNode:s,fromHandle:a,fromPosition:u,to:c,toNode:l,toHandle:f,toPosition:d,pointer:h}=ng();if(!r)return;if(n)return R.jsx(n,{connectionLineType:t,connectionLineStyle:e,fromNode:s,fromHandle:a,fromX:i.x,fromY:i.y,toX:c.x,toY:c.y,fromPosition:u,toPosition:d,connectionStatus:mi(o),toNode:l,toHandle:f,pointer:h});let g="";const _={sourceX:i.x,sourceY:i.y,sourcePosition:u,targetX:c.x,targetY:c.y,targetPosition:d};switch(t){case $e.Bezier:[g]=Ii(_);break;case $e.SimpleBezier:[g]=ss(_);break;case $e.Step:[g]=jn({..._,borderRadius:0});break;case $e.SmoothStep:[g]=jn(_);break;default:[g]=ki(_)}return R.jsx("path",{d:g,fill:"none",className:"react-flow__connection-path",style:e})};ws.displayName="ConnectionLine";const ig={};function Pr(e=ig){D.useRef(e),oe(),D.useEffect(()=>{},[e])}function sg(){oe(),D.useRef(!1),D.useEffect(()=>{},[])}function vs({nodeTypes:e,edgeTypes:t,onInit:n,onNodeClick:o,onEdgeClick:r,onNodeDoubleClick:i,onEdgeDoubleClick:s,onNodeMouseEnter:a,onNodeMouseMove:u,onNodeMouseLeave:c,onNodeContextMenu:l,onSelectionContextMenu:f,onSelectionStart:d,onSelectionEnd:h,connectionLineType:g,connectionLineStyle:_,connectionLineComponent:w,connectionLineContainerStyle:y,selectionKeyCode:C,selectionOnDrag:p,selectionMode:v,multiSelectionKeyCode:A,panActivationKeyCode:S,zoomActivationKeyCode:b,deleteKeyCode:T,onlyRenderVisibleElements:k,elementsSelectable:F,defaultViewport:z,translateExtent:B,minZoom:O,maxZoom:x,preventScrolling:M,defaultMarkerColor:N,zoomOnScroll:I,zoomOnPinch:$,panOnScroll:P,panOnScrollSpeed:j,panOnScrollMode:m,zoomOnDoubleClick:E,panOnDrag:V,autoPanOnSelection:L,onPaneClick:Y,onPaneMouseEnter:W,onPaneMouseMove:Z,onPaneMouseLeave:H,onPaneScroll:X,onPaneContextMenu:J,paneClickDistance:Q,nodeClickDistance:q,onEdgeContextMenu:U,onEdgeMouseEnter:ee,onEdgeMouseMove:ne,onEdgeMouseLeave:re,reconnectRadius:ce,onReconnect:Ce,onReconnectStart:we,onReconnectEnd:ve,noDragClassName:Ne,noWheelClassName:it,noPanClassName:He,disableKeyboardA11y:ze,nodeExtent:de,rfId:Me,viewport:Ae,onViewportChange:Oe,nodesDraggable:gn}){return Pr(e),Pr(t),sg(),Kh(n),Jh(Ae),R.jsx(Eh,{onPaneClick:Y,onPaneMouseEnter:W,onPaneMouseMove:Z,onPaneMouseLeave:H,onPaneContextMenu:J,onPaneScroll:X,paneClickDistance:Q,deleteKeyCode:T,selectionKeyCode:C,selectionOnDrag:p,selectionMode:v,onSelectionStart:d,onSelectionEnd:h,multiSelectionKeyCode:A,panActivationKeyCode:S,zoomActivationKeyCode:b,elementsSelectable:F,zoomOnScroll:I,zoomOnPinch:$,zoomOnDoubleClick:E,panOnScroll:P,panOnScrollSpeed:j,panOnScrollMode:m,panOnDrag:V,autoPanOnSelection:L,defaultViewport:z,translateExtent:B,minZoom:O,maxZoom:x,onSelectionContextMenu:f,preventScrolling:M,noDragClassName:Ne,noWheelClassName:it,noPanClassName:He,disableKeyboardA11y:ze,onViewportChange:Oe,isControlledViewport:!!Ae,children:R.jsxs(Uh,{children:[R.jsx(Gh,{edgeTypes:t,onEdgeClick:r,onEdgeDoubleClick:s,onReconnect:Ce,onReconnectStart:we,onReconnectEnd:ve,onlyRenderVisibleElements:k,onEdgeContextMenu:U,onEdgeMouseEnter:ee,onEdgeMouseMove:ne,onEdgeMouseLeave:re,reconnectRadius:ce,defaultMarkerColor:N,noPanClassName:He,disableKeyboardA11y:ze,rfId:Me}),R.jsx(rg,{style:_,type:g,component:w,containerStyle:y}),R.jsx("div",{className:"react-flow__edgelabel-renderer"}),R.jsx(kh,{nodeTypes:e,onNodeClick:o,onNodeDoubleClick:i,onNodeMouseEnter:a,onNodeMouseMove:u,onNodeMouseLeave:c,onNodeContextMenu:l,nodeClickDistance:q,onlyRenderVisibleElements:k,noPanClassName:He,noDragClassName:Ne,disableKeyboardA11y:ze,nodeExtent:de,rfId:Me,nodesDraggable:gn}),R.jsx("div",{className:"react-flow__viewport-portal"})]})})}vs.displayName="GraphView";const ag=D.memo(vs),cg=Ei(),$r=({nodes:e,edges:t,defaultNodes:n,defaultEdges:o,width:r,height:i,fitView:s,fitViewOptions:a,minZoom:u=.5,maxZoom:c=2,nodeOrigin:l,nodeExtent:f,zIndexMode:d="basic"}={})=>{const h=new Map,g=new Map,_=new Map,w=new Map,y=o??t??[],C=n??e??[],p=l??[0,0],v=f??yt;$i(_,w,y);const{nodesInitialized:A}=Yn(C,h,g,{nodeOrigin:p,nodeExtent:v,zIndexMode:d});let S=[0,0,1];if(s&&r&&i){const b=Ct(h,{filter:z=>!!((z.width||z.initialWidth)&&(z.height||z.initialHeight))}),{x:T,y:k,zoom:F}=oo(b,r,i,u,c,a?.padding??.1);S=[T,k,F]}return{rfId:"1",width:r??0,height:i??0,transform:S,nodes:C,nodesInitialized:A,nodeLookup:h,parentLookup:g,edges:y,edgeLookup:w,connectionLookup:_,onNodesChange:null,onEdgesChange:null,hasDefaultNodes:n!==void 0,hasDefaultEdges:o!==void 0,panZoom:null,minZoom:u,maxZoom:c,translateExtent:yt,nodeExtent:v,nodesSelectionActive:!1,userSelectionActive:!1,userSelectionRect:null,connectionMode:tt.Strict,domNode:null,paneDragging:!1,noPanClassName:"nopan",nodeOrigin:p,nodeDragThreshold:1,connectionDragThreshold:1,snapGrid:[15,15],snapToGrid:!1,nodesDraggable:!0,nodesConnectable:!0,nodesFocusable:!0,edgesFocusable:!0,edgesReconnectable:!0,elementsSelectable:!0,elevateNodesOnSelect:!0,elevateEdgesOnSelect:!0,selectNodesOnDrag:!0,multiSelectionActive:!1,fitViewQueued:s??!1,fitViewOptions:a,fitViewResolver:null,connection:{...pi},connectionClickStartHandle:null,connectOnClick:!0,ariaLiveMessage:"",autoPanOnConnect:!0,autoPanOnNodeDrag:!0,autoPanOnNodeFocus:!0,autoPanSpeed:15,connectionRadius:20,onError:cg,isValidConnection:void 0,onSelectionChangeHandlers:[],lib:"react",debug:!1,ariaLabelConfig:gi,zIndexMode:d,onNodesChangeMiddlewareMap:new Map,onEdgesChangeMiddlewareMap:new Map}},ug=({nodes:e,edges:t,defaultNodes:n,defaultEdges:o,width:r,height:i,fitView:s,fitViewOptions:a,minZoom:u,maxZoom:c,nodeOrigin:l,nodeExtent:f,zIndexMode:d})=>_d((h,g)=>{async function _(){const{nodeLookup:w,panZoom:y,fitViewOptions:C,fitViewResolver:p,width:v,height:A,minZoom:S,maxZoom:b}=g();y&&(await yf({nodes:w,width:v,height:A,panZoom:y,minZoom:S,maxZoom:b},C),p?.resolve(!0),h({fitViewResolver:null}))}return{...$r({nodes:e,edges:t,width:r,height:i,fitView:s,fitViewOptions:a,minZoom:u,maxZoom:c,nodeOrigin:l,nodeExtent:f,defaultNodes:n,defaultEdges:o,zIndexMode:d}),setNodes:w=>{const{nodeLookup:y,parentLookup:C,nodeOrigin:p,elevateNodesOnSelect:v,fitViewQueued:A,zIndexMode:S,nodesSelectionActive:b}=g(),{nodesInitialized:T,hasSelectedNodes:k}=Yn(w,y,C,{nodeOrigin:p,nodeExtent:f,elevateNodesOnSelect:v,checkEquality:!0,zIndexMode:S}),F=b&&k;A&&T?(_(),h({nodes:w,nodesInitialized:T,fitViewQueued:!1,fitViewOptions:void 0,nodesSelectionActive:F})):h({nodes:w,nodesInitialized:T,nodesSelectionActive:F})},setEdges:w=>{const{connectionLookup:y,edgeLookup:C}=g();$i(y,C,w),h({edges:w})},setDefaultNodesAndEdges:(w,y)=>{if(w){const{setNodes:C}=g();C(w),h({hasDefaultNodes:!0})}if(y){const{setEdges:C}=g();C(y),h({hasDefaultEdges:!0})}},updateNodeInternals:w=>{const{triggerNodeChanges:y,nodeLookup:C,parentLookup:p,domNode:v,nodeOrigin:A,nodeExtent:S,debug:b,fitViewQueued:T,zIndexMode:k}=g(),{changes:F,updatedInternals:z}=Vf(w,C,p,v,A,S,k);z&&(Hf(C,p,{nodeOrigin:A,nodeExtent:S,zIndexMode:k}),T?(_(),h({fitViewQueued:!1,fitViewOptions:void 0})):h({}),F?.length>0&&(b&&console.log("React Flow: trigger node changes",F),y?.(F)))},updateNodePositions:(w,y=!1)=>{const C=[];let p=[];const{nodeLookup:v,triggerNodeChanges:A,connection:S,updateConnection:b,onNodesChangeMiddlewareMap:T}=g();for(const[k,F]of w){const z=v.get(k),B=!!(z?.expandParent&&z?.parentId&&F?.position),O={id:k,type:"position",position:B?{x:Math.max(0,F.position.x),y:Math.max(0,F.position.y)}:F.position,dragging:y};if(z&&S.inProgress&&S.fromNode.id===z.id){const x=We(z,S.fromHandle,G.Left,!0);b({...S,from:x})}B&&z.parentId&&C.push({id:k,parentId:z.parentId,rect:{...F.internals.positionAbsolute,width:F.measured.width??0,height:F.measured.height??0}}),p.push(O)}if(C.length>0){const{parentLookup:k,nodeOrigin:F}=g(),z=uo(C,v,k,F);p.push(...z)}for(const k of T.values())p=k(p);A(p)},triggerNodeChanges:w=>{const{onNodesChange:y,setNodes:C,nodes:p,hasDefaultNodes:v,debug:A}=g();if(w?.length){if(v){const S=jd(w,p);C(S)}A&&console.log("React Flow: trigger node changes",w),y?.(w)}},triggerEdgeChanges:w=>{const{onEdgesChange:y,setEdges:C,edges:p,hasDefaultEdges:v,debug:A}=g();if(w?.length){if(v){const S=Fd(w,p);C(S)}A&&console.log("React Flow: trigger edge changes",w),y?.(w)}},addSelectedNodes:w=>{const{multiSelectionActive:y,edgeLookup:C,nodeLookup:p,triggerNodeChanges:v,triggerEdgeChanges:A}=g();if(y){const S=w.map(b=>Le(b,!0));v(S);return}v(Ue(p,new Set([...w]),!0)),A(Ue(C))},addSelectedEdges:w=>{const{multiSelectionActive:y,edgeLookup:C,nodeLookup:p,triggerNodeChanges:v,triggerEdgeChanges:A}=g();if(y){const S=w.map(b=>Le(b,!0));A(S);return}A(Ue(C,new Set([...w]))),v(Ue(p,new Set,!0))},unselectNodesAndEdges:({nodes:w,edges:y}={})=>{const{edges:C,nodes:p,nodeLookup:v,triggerNodeChanges:A,triggerEdgeChanges:S}=g(),b=w||p,T=y||C,k=[];for(const z of b){if(!z.selected)continue;const B=v.get(z.id);B&&(B.selected=!1),k.push(Le(z.id,!1))}const F=[];for(const z of T)z.selected&&F.push(Le(z.id,!1));A(k),S(F)},setMinZoom:w=>{const{panZoom:y,maxZoom:C}=g();y?.setScaleExtent([w,C]),h({minZoom:w})},setMaxZoom:w=>{const{panZoom:y,minZoom:C}=g();y?.setScaleExtent([C,w]),h({maxZoom:w})},setTranslateExtent:w=>{g().panZoom?.setTranslateExtent(w),h({translateExtent:w})},resetSelectedElements:()=>{const{edges:w,nodes:y,triggerNodeChanges:C,triggerEdgeChanges:p,elementsSelectable:v}=g();if(!v)return;const A=y.reduce((b,T)=>T.selected?[...b,Le(T.id,!1)]:b,[]),S=w.reduce((b,T)=>T.selected?[...b,Le(T.id,!1)]:b,[]);C(A),p(S)},setNodeExtent:w=>{const{nodes:y,nodeLookup:C,parentLookup:p,nodeOrigin:v,elevateNodesOnSelect:A,nodeExtent:S,zIndexMode:b}=g();w[0][0]===S[0][0]&&w[0][1]===S[0][1]&&w[1][0]===S[1][0]&&w[1][1]===S[1][1]||(Yn(y,C,p,{nodeOrigin:v,nodeExtent:w,elevateNodesOnSelect:A,checkEquality:!1,zIndexMode:b}),h({nodeExtent:w}))},panBy:w=>{const{transform:y,width:C,height:p,panZoom:v,translateExtent:A}=g();return Bf({delta:w,panZoom:v,transform:y,translateExtent:A,width:C,height:p})},setCenter:async(w,y,C)=>{const{width:p,height:v,maxZoom:A,panZoom:S}=g();if(!S)return!1;const b=typeof C?.zoom<"u"?C.zoom:A;return await S.setViewport({x:p/2-w*b,y:v/2-y*b,zoom:b},{duration:C?.duration,ease:C?.ease,interpolate:C?.interpolate}),!0},cancelConnection:()=>{h({connection:{...pi}})},updateConnection:w=>{h({connection:w})},reset:()=>h({...$r()})}},Object.is);function lg({initialNodes:e,initialEdges:t,defaultNodes:n,defaultEdges:o,initialWidth:r,initialHeight:i,initialMinZoom:s,initialMaxZoom:a,initialFitViewOptions:u,fitView:c,nodeOrigin:l,nodeExtent:f,zIndexMode:d,children:h}){const[g]=D.useState(()=>ug({nodes:e,edges:t,defaultNodes:n,defaultEdges:o,width:r,height:i,fitView:c,minZoom:s,maxZoom:a,fitViewOptions:u,nodeOrigin:l,nodeExtent:f,zIndexMode:d}));return R.jsx(Ed,{value:g,children:R.jsx(qd,{children:R.jsx(uh,{children:h})})})}function fg({children:e,nodes:t,edges:n,defaultNodes:o,defaultEdges:r,width:i,height:s,fitView:a,fitViewOptions:u,minZoom:c,maxZoom:l,nodeOrigin:f,nodeExtent:d,zIndexMode:h}){return D.useContext(ln)?R.jsx(R.Fragment,{children:e}):R.jsx(lg,{initialNodes:t,initialEdges:n,defaultNodes:o,defaultEdges:r,initialWidth:i,initialHeight:s,fitView:a,initialFitViewOptions:u,initialMinZoom:c,initialMaxZoom:l,nodeOrigin:f,nodeExtent:d,zIndexMode:h,children:e})}const dg={width:"100%",height:"100%",overflow:"hidden",position:"relative",zIndex:0};function hg({nodes:e,edges:t,defaultNodes:n,defaultEdges:o,className:r,nodeTypes:i,edgeTypes:s,onNodeClick:a,onEdgeClick:u,onInit:c,onMove:l,onMoveStart:f,onMoveEnd:d,onConnect:h,onConnectStart:g,onConnectEnd:_,onClickConnectStart:w,onClickConnectEnd:y,onNodeMouseEnter:C,onNodeMouseMove:p,onNodeMouseLeave:v,onNodeContextMenu:A,onNodeDoubleClick:S,onNodeDragStart:b,onNodeDrag:T,onNodeDragStop:k,onNodesDelete:F,onEdgesDelete:z,onDelete:B,onSelectionChange:O,onSelectionDragStart:x,onSelectionDrag:M,onSelectionDragStop:N,onSelectionContextMenu:I,onSelectionStart:$,onSelectionEnd:P,onBeforeDelete:j,connectionMode:m,connectionLineType:E=$e.Bezier,connectionLineStyle:V,connectionLineComponent:L,connectionLineContainerStyle:Y,deleteKeyCode:W="Backspace",selectionKeyCode:Z="Shift",selectionOnDrag:H=!1,selectionMode:X=xt.Full,panActivationKeyCode:J="Space",multiSelectionKeyCode:Q=vt()?"Meta":"Control",zoomActivationKeyCode:q=vt()?"Meta":"Control",snapToGrid:U,snapGrid:ee,onlyRenderVisibleElements:ne=!1,selectNodesOnDrag:re,nodesDraggable:ce,autoPanOnNodeFocus:Ce,nodesConnectable:we,nodesFocusable:ve,nodeOrigin:Ne=Wi,edgesFocusable:it,edgesReconnectable:He,elementsSelectable:ze=!0,defaultViewport:de=Dd,minZoom:Me=.5,maxZoom:Ae=2,translateExtent:Oe=yt,preventScrolling:gn=!0,nodeExtent:pn,defaultMarkerColor:Ss="#b1b1b7",zoomOnScroll:Cs=!0,zoomOnPinch:Ns=!0,panOnScroll:Ms=!1,panOnScrollSpeed:As=.5,panOnScrollMode:Is=je.Free,zoomOnDoubleClick:Ts=!0,panOnDrag:ks=!0,onPaneClick:Rs,onPaneMouseEnter:Ps,onPaneMouseMove:$s,onPaneMouseLeave:Ds,onPaneScroll:Hs,onPaneContextMenu:zs,paneClickDistance:Os=1,nodeClickDistance:Ls=0,children:Vs,onReconnect:Bs,onReconnectStart:js,onReconnectEnd:Fs,onEdgeContextMenu:Ys,onEdgeDoubleClick:Xs,onEdgeMouseEnter:Zs,onEdgeMouseMove:Ws,onEdgeMouseLeave:qs,reconnectRadius:Gs=10,onNodesChange:Us,onEdgesChange:Ks,noDragClassName:Qs="nodrag",noWheelClassName:Js="nowheel",noPanClassName:ho="nopan",fitView:go,fitViewOptions:po,connectOnClick:ea,attributionPosition:ta,proOptions:na,defaultEdgeOptions:oa,elevateNodesOnSelect:ra=!0,elevateEdgesOnSelect:ia=!1,disableKeyboardA11y:mo=!1,autoPanOnConnect:sa,autoPanOnNodeDrag:aa,autoPanOnSelection:ca=!0,autoPanSpeed:ua,connectionRadius:la,isValidConnection:fa,onError:da,style:ha,id:yo,nodeDragThreshold:ga,connectionDragThreshold:pa,viewport:ma,onViewportChange:ya,width:xa,height:wa,colorMode:va="light",debug:_a,onScroll:xo,ariaLabelConfig:Ea,zIndexMode:wo="basic",...ba},Sa){const mn=yo||"1",Ca=Ld(va),Na=D.useCallback(vo=>{vo.currentTarget.scrollTo({top:0,left:0,behavior:"instant"}),xo?.(vo)},[xo]);return R.jsx("div",{"data-testid":"rf__wrapper",...ba,onScroll:Na,style:{...ha,...dg},ref:Sa,className:se(["react-flow",r,Ca]),id:yo,role:"application",children:R.jsxs(fg,{nodes:e,edges:t,width:xa,height:wa,fitView:go,fitViewOptions:po,minZoom:Me,maxZoom:Ae,nodeOrigin:Ne,nodeExtent:pn,zIndexMode:wo,children:[R.jsx(Od,{nodes:e,edges:t,defaultNodes:n,defaultEdges:o,onConnect:h,onConnectStart:g,onConnectEnd:_,onClickConnectStart:w,onClickConnectEnd:y,nodesDraggable:ce,autoPanOnNodeFocus:Ce,nodesConnectable:we,nodesFocusable:ve,edgesFocusable:it,edgesReconnectable:He,elementsSelectable:ze,elevateNodesOnSelect:ra,elevateEdgesOnSelect:ia,minZoom:Me,maxZoom:Ae,nodeExtent:pn,onNodesChange:Us,onEdgesChange:Ks,snapToGrid:U,snapGrid:ee,connectionMode:m,translateExtent:Oe,connectOnClick:ea,defaultEdgeOptions:oa,fitView:go,fitViewOptions:po,onNodesDelete:F,onEdgesDelete:z,onDelete:B,onNodeDragStart:b,onNodeDrag:T,onNodeDragStop:k,onSelectionDrag:M,onSelectionDragStart:x,onSelectionDragStop:N,onMove:l,onMoveStart:f,onMoveEnd:d,noPanClassName:ho,nodeOrigin:Ne,rfId:mn,autoPanOnConnect:sa,autoPanOnNodeDrag:aa,autoPanSpeed:ua,onError:da,connectionRadius:la,isValidConnection:fa,selectNodesOnDrag:re,nodeDragThreshold:ga,connectionDragThreshold:pa,onBeforeDelete:j,debug:_a,ariaLabelConfig:Ea,zIndexMode:wo}),R.jsx(ag,{onInit:c,onNodeClick:a,onEdgeClick:u,onNodeMouseEnter:C,onNodeMouseMove:p,onNodeMouseLeave:v,onNodeContextMenu:A,onNodeDoubleClick:S,nodeTypes:i,edgeTypes:s,connectionLineType:E,connectionLineStyle:V,connectionLineComponent:L,connectionLineContainerStyle:Y,selectionKeyCode:Z,selectionOnDrag:H,selectionMode:X,deleteKeyCode:W,multiSelectionKeyCode:Q,panActivationKeyCode:J,zoomActivationKeyCode:q,onlyRenderVisibleElements:ne,defaultViewport:de,translateExtent:Oe,minZoom:Me,maxZoom:Ae,preventScrolling:gn,zoomOnScroll:Cs,zoomOnPinch:Ns,zoomOnDoubleClick:Ts,panOnScroll:Ms,panOnScrollSpeed:As,panOnScrollMode:Is,panOnDrag:ks,autoPanOnSelection:ca,onPaneClick:Rs,onPaneMouseEnter:Ps,onPaneMouseMove:$s,onPaneMouseLeave:Ds,onPaneScroll:Hs,onPaneContextMenu:zs,paneClickDistance:Os,nodeClickDistance:Ls,onSelectionContextMenu:I,onSelectionStart:$,onSelectionEnd:P,onReconnect:Bs,onReconnectStart:js,onReconnectEnd:Fs,onEdgeContextMenu:Ys,onEdgeDoubleClick:Xs,onEdgeMouseEnter:Zs,onEdgeMouseMove:Ws,onEdgeMouseLeave:qs,reconnectRadius:Gs,defaultMarkerColor:Ss,noDragClassName:Qs,noWheelClassName:Js,noPanClassName:ho,rfId:mn,disableKeyboardA11y:mo,nodeExtent:pn,viewport:ma,onViewportChange:ya,nodesDraggable:ce}),R.jsx($d,{onSelectionChange:O}),Vs,R.jsx(Id,{proOptions:na,position:ta}),R.jsx(Ad,{rfId:mn,disableKeyboardA11y:mo})]})})}var jg=Gi(hg);const gg=e=>({x:e.transform[0],y:e.transform[1],zoom:e.transform[2]});function Fg(){return te(gg,ie)}function pg({dimensions:e,lineWidth:t,variant:n,className:o}){return R.jsx("path",{strokeWidth:t,d:`M${e[0]/2} 0 V${e[1]} M0 ${e[1]/2} H${e[0]}`,className:se(["react-flow__background-pattern",n,o])})}function mg({radius:e,className:t}){return R.jsx("circle",{cx:e,cy:e,r:e,className:se(["react-flow__background-pattern","dots",t])})}var De;(function(e){e.Lines="lines",e.Dots="dots",e.Cross="cross"})(De||(De={}));const yg={[De.Dots]:1,[De.Lines]:1,[De.Cross]:6},xg=e=>({transform:e.transform,patternId:`pattern-${e.rfId}`});function _s({id:e,variant:t=De.Dots,gap:n=20,size:o,lineWidth:r=1,offset:i=0,color:s,bgColor:a,style:u,className:c,patternClassName:l}){const f=D.useRef(null),{transform:d,patternId:h}=te(xg,ie),g=o||yg[t],_=t===De.Dots,w=t===De.Cross,y=Array.isArray(n)?n:[n,n],C=[y[0]*d[2]||1,y[1]*d[2]||1],p=g*d[2],v=Array.isArray(i)?i:[i,i],A=w?[p,p]:C,S=[v[0]*d[2]||1+A[0]/2,v[1]*d[2]||1+A[1]/2],b=`${h}${e||""}`;return R.jsxs("svg",{className:se(["react-flow__background",c]),style:{...u,...dn,"--xy-background-color-props":a,"--xy-background-pattern-color-props":s},ref:f,"data-testid":"rf__background",children:[R.jsx("pattern",{id:b,x:d[0]%C[0],y:d[1]%C[1],width:C[0],height:C[1],patternUnits:"userSpaceOnUse",patternTransform:`translate(-${S[0]},-${S[1]})`,children:_?R.jsx(mg,{radius:p/2,className:l}):R.jsx(pg,{dimensions:A,lineWidth:r,variant:t,className:l})}),R.jsx("rect",{x:"0",y:"0",width:"100%",height:"100%",fill:`url(#${b})`})]})}_s.displayName="Background";const Yg=D.memo(_s);function wg(){return R.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 32",children:R.jsx("path",{d:"M32 18.133H18.133V32h-4.266V18.133H0v-4.266h13.867V0h4.266v13.867H32z"})})}function vg(){return R.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 5",children:R.jsx("path",{d:"M0 0h32v4.2H0z"})})}function _g(){return R.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 32 30",children:R.jsx("path",{d:"M3.692 4.63c0-.53.4-.938.939-.938h5.215V0H4.708C2.13 0 0 2.054 0 4.63v5.216h3.692V4.631zM27.354 0h-5.2v3.692h5.17c.53 0 .984.4.984.939v5.215H32V4.631A4.624 4.624 0 0027.354 0zm.954 24.83c0 .532-.4.94-.939.94h-5.215v3.768h5.215c2.577 0 4.631-2.13 4.631-4.707v-5.139h-3.692v5.139zm-23.677.94c-.531 0-.939-.4-.939-.94v-5.138H0v5.139c0 2.577 2.13 4.707 4.708 4.707h5.138V25.77H4.631z"})})}function Eg(){return R.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:R.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0 8 0 4.571 3.429 4.571 7.619v3.048H3.048A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047zm4.724-13.866H7.467V7.619c0-2.59 2.133-4.724 4.723-4.724 2.591 0 4.724 2.133 4.724 4.724v3.048z"})})}function bg(){return R.jsx("svg",{xmlns:"http://www.w3.org/2000/svg",viewBox:"0 0 25 32",children:R.jsx("path",{d:"M21.333 10.667H19.81V7.619C19.81 3.429 16.38 0 12.19 0c-4.114 1.828-1.37 2.133.305 2.438 1.676.305 4.42 2.59 4.42 5.181v3.048H3.047A3.056 3.056 0 000 13.714v15.238A3.056 3.056 0 003.048 32h18.285a3.056 3.056 0 003.048-3.048V13.714a3.056 3.056 0 00-3.048-3.047zM12.19 24.533a3.056 3.056 0 01-3.047-3.047 3.056 3.056 0 013.047-3.048 3.056 3.056 0 013.048 3.048 3.056 3.056 0 01-3.048 3.047z"})})}function Ht({children:e,className:t,...n}){return R.jsx("button",{type:"button",className:se(["react-flow__controls-button",t]),...n,children:e})}const Sg=e=>({isInteractive:e.nodesDraggable||e.nodesConnectable||e.elementsSelectable,minZoomReached:e.transform[2]<=e.minZoom,maxZoomReached:e.transform[2]>=e.maxZoom,ariaLabelConfig:e.ariaLabelConfig});function Es({style:e,showZoom:t=!0,showFitView:n=!0,showInteractive:o=!0,fitViewOptions:r,onZoomIn:i,onZoomOut:s,onFitView:a,onInteractiveChange:u,className:c,children:l,position:f="bottom-left",orientation:d="vertical","aria-label":h}){const g=oe(),{isInteractive:_,minZoomReached:w,maxZoomReached:y,ariaLabelConfig:C}=te(Sg,ie),{zoomIn:p,zoomOut:v,fitView:A}=lo(),S=()=>{p(),i?.()},b=()=>{v(),s?.()},T=()=>{A(r),a?.()},k=()=>{g.setState({nodesDraggable:!_,nodesConnectable:!_,elementsSelectable:!_}),u?.(!_)},F=d==="horizontal"?"horizontal":"vertical";return R.jsxs(fn,{className:se(["react-flow__controls",F,c]),position:f,style:e,"data-testid":"rf__controls","aria-label":h??C["controls.ariaLabel"],children:[t&&R.jsxs(R.Fragment,{children:[R.jsx(Ht,{onClick:S,className:"react-flow__controls-zoomin",title:C["controls.zoomIn.ariaLabel"],"aria-label":C["controls.zoomIn.ariaLabel"],disabled:y,children:R.jsx(wg,{})}),R.jsx(Ht,{onClick:b,className:"react-flow__controls-zoomout",title:C["controls.zoomOut.ariaLabel"],"aria-label":C["controls.zoomOut.ariaLabel"],disabled:w,children:R.jsx(vg,{})})]}),n&&R.jsx(Ht,{className:"react-flow__controls-fitview",onClick:T,title:C["controls.fitView.ariaLabel"],"aria-label":C["controls.fitView.ariaLabel"],children:R.jsx(_g,{})}),o&&R.jsx(Ht,{className:"react-flow__controls-interactive",onClick:k,title:C["controls.interactive.ariaLabel"],"aria-label":C["controls.interactive.ariaLabel"],children:_?R.jsx(bg,{}):R.jsx(Eg,{})}),l]})}Es.displayName="Controls";const Xg=D.memo(Es);function Cg({id:e,x:t,y:n,width:o,height:r,style:i,color:s,strokeColor:a,strokeWidth:u,className:c,borderRadius:l,shapeRendering:f,selected:d,onClick:h}){const{background:g,backgroundColor:_}=i||{},w=s||g||_;return R.jsx("rect",{className:se(["react-flow__minimap-node",{selected:d},c]),x:t,y:n,rx:l,ry:l,width:o,height:r,style:{fill:w,stroke:a,strokeWidth:u},shapeRendering:f,onClick:h?y=>h(y,e):void 0})}const Ng=D.memo(Cg),Mg=e=>e.nodes.map(t=>t.id),Rn=e=>e instanceof Function?e:()=>e;function Ag({nodeStrokeColor:e,nodeColor:t,nodeClassName:n="",nodeBorderRadius:o=5,nodeStrokeWidth:r,nodeComponent:i=Ng,onClick:s}){const a=te(Mg,ie),u=Rn(t),c=Rn(e),l=Rn(n),f=typeof window>"u"||window.chrome?"crispEdges":"geometricPrecision";return R.jsx(R.Fragment,{children:a.map(d=>R.jsx(Tg,{id:d,nodeColorFunc:u,nodeStrokeColorFunc:c,nodeClassNameFunc:l,nodeBorderRadius:o,nodeStrokeWidth:r,NodeComponent:i,onClick:s,shapeRendering:f},d))})}function Ig({id:e,nodeColorFunc:t,nodeStrokeColorFunc:n,nodeClassNameFunc:o,nodeBorderRadius:r,nodeStrokeWidth:i,shapeRendering:s,NodeComponent:a,onClick:u}){const{node:c,x:l,y:f,width:d,height:h}=te(g=>{const _=g.nodeLookup.get(e);if(!_)return{node:void 0,x:0,y:0,width:0,height:0};const w=_.internals.userNode,{x:y,y:C}=_.internals.positionAbsolute,{width:p,height:v}=Se(w);return{node:w,x:y,y:C,width:p,height:v}},ie);return!c||c.hidden||!bi(c)?null:R.jsx(a,{x:l,y:f,width:d,height:h,style:c.style,selected:!!c.selected,className:o(c),color:t(c),borderRadius:r,strokeColor:n(c),strokeWidth:i,shapeRendering:s,onClick:u,id:c.id})}const Tg=D.memo(Ig);var kg=D.memo(Ag);const Rg=200,Pg=150,$g=e=>!e.hidden,Dg=e=>{const t={x:-e.transform[0]/e.transform[2],y:-e.transform[1]/e.transform[2],width:e.width/e.transform[2],height:e.height/e.transform[2]};return{viewBB:t,boundingRect:e.nodeLookup.size>0?vi(Ct(e.nodeLookup,{filter:$g}),t):t,rfId:e.rfId,panZoom:e.panZoom,translateExtent:e.translateExtent,flowWidth:e.width,flowHeight:e.height,ariaLabelConfig:e.ariaLabelConfig}},Dr=(e,t)=>e.x===t.x&&e.y===t.y&&e.width===t.width&&e.height===t.height,Hg=(e,t)=>Dr(e.viewBB,t.viewBB)&&Dr(e.boundingRect,t.boundingRect)&&e.rfId===t.rfId&&e.panZoom===t.panZoom&&e.translateExtent===t.translateExtent&&e.flowWidth===t.flowWidth&&e.flowHeight===t.flowHeight&&e.ariaLabelConfig===t.ariaLabelConfig,zg="react-flow__minimap-desc";function bs({style:e,className:t,nodeStrokeColor:n,nodeColor:o,nodeClassName:r="",nodeBorderRadius:i=5,nodeStrokeWidth:s,nodeComponent:a,bgColor:u,maskColor:c,maskStrokeColor:l,maskStrokeWidth:f,position:d="bottom-right",onClick:h,onNodeClick:g,pannable:_=!1,zoomable:w=!1,ariaLabel:y,inversePan:C,zoomStep:p=1,offsetScale:v=5}){const A=oe(),S=D.useRef(null),{boundingRect:b,viewBB:T,rfId:k,panZoom:F,translateExtent:z,flowWidth:B,flowHeight:O,ariaLabelConfig:x}=te(Dg,Hg),M=e?.width??Rg,N=e?.height??Pg,I=b.width/M,$=b.height/N,P=Math.max(I,$),j=P*M,m=P*N,E=v*P,V=b.x-(j-b.width)/2-E,L=b.y-(m-b.height)/2-E,Y=j+E*2,W=m+E*2,Z=`${zg}-${k}`,H=D.useRef(0),X=D.useRef();H.current=P,D.useEffect(()=>{if(S.current&&F)return X.current=Uf({domNode:S.current,panZoom:F,getTransform:()=>A.getState().transform,getViewScale:()=>H.current}),()=>{X.current?.destroy()}},[F]),D.useEffect(()=>{X.current?.update({translateExtent:z,width:B,height:O,inversePan:C,pannable:_,zoomStep:p,zoomable:w})},[_,w,C,p,z,B,O]);const J=h?U=>{const[ee,ne]=X.current?.pointer(U)||[0,0];h(U,{x:ee,y:ne})}:void 0,Q=g?D.useCallback((U,ee)=>{const ne=A.getState().nodeLookup.get(ee).internals.userNode;g(U,ne)},[]):void 0,q=y??x["minimap.ariaLabel"];return R.jsx(fn,{position:d,style:{...e,"--xy-minimap-background-color-props":typeof u=="string"?u:void 0,"--xy-minimap-mask-background-color-props":typeof c=="string"?c:void 0,"--xy-minimap-mask-stroke-color-props":typeof l=="string"?l:void 0,"--xy-minimap-mask-stroke-width-props":typeof f=="number"?f*P:void 0,"--xy-minimap-node-background-color-props":typeof o=="string"?o:void 0,"--xy-minimap-node-stroke-color-props":typeof n=="string"?n:void 0,"--xy-minimap-node-stroke-width-props":typeof s=="number"?s:void 0},className:se(["react-flow__minimap",t]),"data-testid":"rf__minimap",children:R.jsxs("svg",{width:M,height:N,viewBox:`${V} ${L} ${Y} ${W}`,className:"react-flow__minimap-svg",role:"img","aria-labelledby":Z,ref:S,onClick:J,children:[q&&R.jsx("title",{id:Z,children:q}),R.jsx(kg,{onClick:Q,nodeColor:o,nodeStrokeColor:n,nodeBorderRadius:i,nodeClassName:r,nodeStrokeWidth:s,nodeComponent:a}),R.jsx("path",{className:"react-flow__minimap-mask",d:`M${V-E},${L-E}h${Y+E*2}v${W+E*2}h${-Y-E*2}z + M${T.x},${T.y}h${T.width}v${T.height}h${-T.width}z`,fillRule:"evenodd",pointerEvents:"none"})]})})}bs.displayName="MiniMap";D.memo(bs);const Og=e=>t=>e?`${Math.max(1/t.transform[2],1)}`:void 0,Lg={[rt.Line]:"right",[rt.Handle]:"bottom-right"};function Vg({nodeId:e,position:t,variant:n=rt.Handle,className:o,style:r=void 0,children:i,color:s,minWidth:a=10,minHeight:u=10,maxWidth:c=Number.MAX_VALUE,maxHeight:l=Number.MAX_VALUE,keepAspectRatio:f=!1,resizeDirection:d,autoScale:h=!0,shouldResize:g,onResizeStart:_,onResize:w,onResizeEnd:y}){const C=es(),p=typeof e=="string"?e:C,v=oe(),A=D.useRef(null),S=n===rt.Handle,b=te(D.useCallback(Og(S&&h),[S,h]),ie),T=D.useRef(null),k=t??Lg[n];D.useEffect(()=>{if(!(!A.current||!p))return T.current||(T.current=ud({domNode:A.current,nodeId:p,getStoreItems:()=>{const{nodeLookup:z,transform:B,snapGrid:O,snapToGrid:x,nodeOrigin:M,domNode:N}=v.getState();return{nodeLookup:z,transform:B,snapGrid:O,snapToGrid:x,nodeOrigin:M,paneDomNode:N}},onChange:(z,B)=>{const{triggerNodeChanges:O,nodeLookup:x,parentLookup:M,nodeOrigin:N}=v.getState(),I=[],$={x:z.x,y:z.y},P=x.get(p);if(P&&P.expandParent&&P.parentId){const j=P.origin??N,m=z.width??P.measured.width??0,E=z.height??P.measured.height??0,V={id:P.id,parentId:P.parentId,rect:{width:m,height:E,...Si({x:z.x??P.position.x,y:z.y??P.position.y},{width:m,height:E},P.parentId,x,j)}},L=uo([V],x,M,N);I.push(...L),$.x=z.x?Math.max(j[0]*m,z.x):void 0,$.y=z.y?Math.max(j[1]*E,z.y):void 0}if($.x!==void 0&&$.y!==void 0){const j={id:p,type:"position",position:{...$}};I.push(j)}if(z.width!==void 0&&z.height!==void 0){const m={id:p,type:"dimensions",resizing:!0,setAttributes:d?d==="horizontal"?"width":"height":!0,dimensions:{width:z.width,height:z.height}};I.push(m)}for(const j of B){const m={...j,type:"position"};I.push(m)}O(I)},onEnd:({width:z,height:B})=>{const O={id:p,type:"dimensions",resizing:!1,dimensions:{width:z,height:B}};v.getState().triggerNodeChanges([O])}})),T.current.update({controlPosition:k,boundaries:{minWidth:a,minHeight:u,maxWidth:c,maxHeight:l},keepAspectRatio:f,resizeDirection:d,onResizeStart:_,onResize:w,onResizeEnd:y,shouldResize:g}),()=>{T.current?.destroy()}},[k,a,u,c,l,f,_,w,y,g]);const F=k.split("-");return R.jsx("div",{className:se(["react-flow__resize-control","nodrag",...F,n,o]),ref:A,style:{...r,scale:b,...s&&{[S?"backgroundColor":"borderColor"]:s}},children:i})}D.memo(Vg);export{hn as B,Xg as C,Qt as H,Gt as M,G as P,Ra as a,D as b,Fg as c,te as d,fn as e,Yg as f,De as g,Hr as h,jg as i,R as j,Bg as k,en as r,lo as u}; diff --git a/src/runtime/operator/web_assets/assets/index-DITPpSoj.js b/src/runtime/operator/web_assets/assets/index-DITPpSoj.js new file mode 100644 index 0000000..4ef66b9 --- /dev/null +++ b/src/runtime/operator/web_assets/assets/index-DITPpSoj.js @@ -0,0 +1,22 @@ +import{r as z0,a as R0,b as L,j as v,u as O0,c as C0,H as oo,P as so,d as D0,B as M0,i as j0,e as lm,f as L0,g as B0,C as U0,M as I0,h as cg,k as q0}from"./graph-Dj7zaIMl.js";import{S as H0,M as Ee,r as _e,U as ee,W as _,s as hn,G as V0}from"./protobuf-BR9ifi4u.js";import{E as Oa,a as G0,j as Y0,k as F0}from"./editor-Dh6wG2B-.js";(function(){const n=document.createElement("link").relList;if(n&&n.supports&&n.supports("modulepreload"))return;for(const u of document.querySelectorAll('link[rel="modulepreload"]'))o(u);new MutationObserver(u=>{for(const s of u)if(s.type==="childList")for(const d of s.addedNodes)d.tagName==="LINK"&&d.rel==="modulepreload"&&o(d)}).observe(document,{childList:!0,subtree:!0});function i(u){const s={};return u.integrity&&(s.integrity=u.integrity),u.referrerPolicy&&(s.referrerPolicy=u.referrerPolicy),u.crossOrigin==="use-credentials"?s.credentials="include":u.crossOrigin==="anonymous"?s.credentials="omit":s.credentials="same-origin",s}function o(u){if(u.ep)return;u.ep=!0;const s=i(u);fetch(u.href,s)}})();var Fu={exports:{}},Ca={},Xu={exports:{}},Qu={};var im;function X0(){return im||(im=1,(function(a){function n(R,K){var fe=R.length;R.push(K);e:for(;0>>1,w=R[W];if(0>>1;Wu(T,fe))Reu(Ye,T)?(R[W]=Ye,R[Re]=fe,W=Re):(R[W]=T,R[Se]=fe,W=Se);else if(Reu(Ye,fe))R[W]=Ye,R[Re]=fe,W=Re;else break e}}return K}function u(R,K){var fe=R.sortIndex-K.sortIndex;return fe!==0?fe:R.id-K.id}if(a.unstable_now=void 0,typeof performance=="object"&&typeof performance.now=="function"){var s=performance;a.unstable_now=function(){return s.now()}}else{var d=Date,h=d.now();a.unstable_now=function(){return d.now()-h}}var m=[],p=[],g=1,b=null,k=3,S=!1,j=!1,I=!1,X=!1,D=typeof setTimeout=="function"?setTimeout:null,G=typeof clearTimeout=="function"?clearTimeout:null,B=typeof setImmediate<"u"?setImmediate:null;function F(R){for(var K=i(p);K!==null;){if(K.callback===null)o(p);else if(K.startTime<=R)o(p),K.sortIndex=K.expirationTime,n(m,K);else break;K=i(p)}}function te(R){if(I=!1,F(R),!j)if(i(m)!==null)j=!0,q||(q=!0,Z());else{var K=i(p);K!==null&&$(te,K.startTime-R)}}var q=!1,re=-1,ue=5,de=-1;function pe(){return X?!0:!(a.unstable_now()-deR&&pe());){var W=b.callback;if(typeof W=="function"){b.callback=null,k=b.priorityLevel;var w=W(b.expirationTime<=R);if(R=a.unstable_now(),typeof w=="function"){b.callback=w,F(R),K=!0;break t}b===i(m)&&o(m),F(R)}else o(m);b=i(m)}if(b!==null)K=!0;else{var ze=i(p);ze!==null&&$(te,ze.startTime-R),K=!1}}break e}finally{b=null,k=fe,S=!1}K=void 0}}finally{K?Z():q=!1}}}var Z;if(typeof B=="function")Z=function(){B(le)};else if(typeof MessageChannel<"u"){var me=new MessageChannel,ne=me.port2;me.port1.onmessage=le,Z=function(){ne.postMessage(null)}}else Z=function(){D(le,0)};function $(R,K){re=D(function(){R(a.unstable_now())},K)}a.unstable_IdlePriority=5,a.unstable_ImmediatePriority=1,a.unstable_LowPriority=4,a.unstable_NormalPriority=3,a.unstable_Profiling=null,a.unstable_UserBlockingPriority=2,a.unstable_cancelCallback=function(R){R.callback=null},a.unstable_forceFrameRate=function(R){0>R||125W?(R.sortIndex=fe,n(p,R),i(m)===null&&R===i(p)&&(I?(G(re),re=-1):I=!0,$(te,fe-W))):(R.sortIndex=w,n(m,R),j||S||(j=!0,q||(q=!0,Z()))),R},a.unstable_shouldYield=pe,a.unstable_wrapCallback=function(R){var K=k;return function(){var fe=k;k=K;try{return R.apply(this,arguments)}finally{k=fe}}}})(Qu)),Qu}var am;function Q0(){return am||(am=1,Xu.exports=X0()),Xu.exports}var rm;function K0(){if(rm)return Ca;rm=1;var a=Q0(),n=z0(),i=R0();function o(e){var t="https://react.dev/errors/"+e;if(1w||(e.current=W[w],W[w]=null,w--)}function T(e,t){w++,W[w]=e.current,e.current=t}var Re=ze(null),Ye=ze(null),Le=ze(null),ke=ze(null);function Ke(e,t){switch(T(Le,t),T(Ye,e),T(Re,null),t.nodeType){case 9:case 11:e=(e=t.documentElement)&&(e=e.namespaceURI)?_p(e):0;break;default:if(e=t.tagName,t=t.namespaceURI)t=_p(t),e=Ap(t,e);else switch(e){case"svg":e=1;break;case"math":e=2;break;default:e=0}}Se(Re),T(Re,e)}function We(){Se(Re),Se(Ye),Se(Le)}function Ie(e){e.memoizedState!==null&&T(ke,e);var t=Re.current,l=Ap(t,e.type);t!==l&&(T(Ye,e),T(Re,l))}function Pe(e){Ye.current===e&&(Se(Re),Se(Ye)),ke.current===e&&(Se(ke),Aa._currentValue=fe)}var St,Tt;function nt(e){if(St===void 0)try{throw Error()}catch(l){var t=l.stack.trim().match(/\n( *(at )?)/);St=t&&t[1]||"",Tt=-1)":-1c||E[r]!==C[c]){var H=` +`+E[r].replace(" at new "," at ");return e.displayName&&H.includes("")&&(H=H.replace("",e.displayName)),H}while(1<=r&&0<=c);break}}}finally{jt=!1,Error.prepareStackTrace=l}return(l=e?e.displayName||e.name:"")?nt(l):""}function tn(e,t){switch(e.tag){case 26:case 27:case 5:return nt(e.type);case 16:return nt("Lazy");case 13:return e.child!==t&&t!==null?nt("Suspense Fallback"):nt("Suspense");case 19:return nt("SuspenseList");case 0:case 15:return gn(e.type,!1);case 11:return gn(e.type.render,!1);case 1:return gn(e.type,!0);case 31:return nt("Activity");default:return""}}function Ot(e){try{var t="",l=null;do t+=tn(e,l),l=e,e=e.return;while(e);return t}catch(r){return` +Error generating stack: `+r.message+` +`+r.stack}}var Et=Object.prototype.hasOwnProperty,st=a.unstable_scheduleCallback,xt=a.unstable_cancelCallback,vl=a.unstable_shouldYield,vn=a.unstable_requestPaint,ie=a.unstable_now,ce=a.unstable_getCurrentPriorityLevel,z=a.unstable_ImmediatePriority,J=a.unstable_UserBlockingPriority,ae=a.unstable_NormalPriority,ye=a.unstable_LowPriority,Be=a.unstable_IdlePriority,rt=a.log,ht=a.unstable_setDisableYieldValue,Q=null,se=null;function oe(e){if(typeof rt=="function"&&ht(e),se&&typeof se.setStrictMode=="function")try{se.setStrictMode(Q,e)}catch{}}var be=Math.clz32?Math.clz32:Co,Oe=Math.log,Fe=Math.LN2;function Co(e){return e>>>=0,e===0?32:31-(Oe(e)/Fe|0)|0}var Sl=256,Xa=262144,Qa=4194304;function kl(e){var t=e&42;if(t!==0)return t;switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:return 64;case 128:return 128;case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:return e&261888;case 262144:case 524288:case 1048576:case 2097152:return e&3932160;case 4194304:case 8388608:case 16777216:case 33554432:return e&62914560;case 67108864:return 67108864;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 0;default:return e}}function Ka(e,t,l){var r=e.pendingLanes;if(r===0)return 0;var c=0,f=e.suspendedLanes,y=e.pingedLanes;e=e.warmLanes;var x=r&134217727;return x!==0?(r=x&~f,r!==0?c=kl(r):(y&=x,y!==0?c=kl(y):l||(l=x&~e,l!==0&&(c=kl(l))))):(x=r&~f,x!==0?c=kl(x):y!==0?c=kl(y):l||(l=r&~e,l!==0&&(c=kl(l)))),c===0?0:t!==0&&t!==c&&(t&f)===0&&(f=c&-c,l=t&-t,f>=l||f===32&&(l&4194048)!==0)?t:c}function qi(e,t){return(e.pendingLanes&~(e.suspendedLanes&~e.pingedLanes)&t)===0}function gy(e,t){switch(e){case 1:case 2:case 4:case 8:case 64:return t+250;case 16:case 32:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return t+5e3;case 4194304:case 8388608:case 16777216:case 33554432:return-1;case 67108864:case 134217728:case 268435456:case 536870912:case 1073741824:return-1;default:return-1}}function of(){var e=Qa;return Qa<<=1,(Qa&62914560)===0&&(Qa=4194304),e}function Do(e){for(var t=[],l=0;31>l;l++)t.push(e);return t}function Hi(e,t){e.pendingLanes|=t,t!==268435456&&(e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0)}function yy(e,t,l,r,c,f){var y=e.pendingLanes;e.pendingLanes=l,e.suspendedLanes=0,e.pingedLanes=0,e.warmLanes=0,e.expiredLanes&=l,e.entangledLanes&=l,e.errorRecoveryDisabledLanes&=l,e.shellSuspendCounter=0;var x=e.entanglements,E=e.expirationTimes,C=e.hiddenUpdates;for(l=y&~l;0"u")return null;try{return e.activeElement||e.body}catch{return e.body}}var wy=/[\n"\\]/g;function ln(e){return e.replace(wy,function(t){return"\\"+t.charCodeAt(0).toString(16)+" "})}function Io(e,t,l,r,c,f,y,x){e.name="",y!=null&&typeof y!="function"&&typeof y!="symbol"&&typeof y!="boolean"?e.type=y:e.removeAttribute("type"),t!=null?y==="number"?(t===0&&e.value===""||e.value!=t)&&(e.value=""+nn(t)):e.value!==""+nn(t)&&(e.value=""+nn(t)):y!=="submit"&&y!=="reset"||e.removeAttribute("value"),t!=null?qo(e,y,nn(t)):l!=null?qo(e,y,nn(l)):r!=null&&e.removeAttribute("value"),c==null&&f!=null&&(e.defaultChecked=!!f),c!=null&&(e.checked=c&&typeof c!="function"&&typeof c!="symbol"),x!=null&&typeof x!="function"&&typeof x!="symbol"&&typeof x!="boolean"?e.name=""+nn(x):e.removeAttribute("name")}function vf(e,t,l,r,c,f,y,x){if(f!=null&&typeof f!="function"&&typeof f!="symbol"&&typeof f!="boolean"&&(e.type=f),t!=null||l!=null){if(!(f!=="submit"&&f!=="reset"||t!=null)){Uo(e);return}l=l!=null?""+nn(l):"",t=t!=null?""+nn(t):l,x||t===e.value||(e.value=t),e.defaultValue=t}r=r??c,r=typeof r!="function"&&typeof r!="symbol"&&!!r,e.checked=x?e.checked:!!r,e.defaultChecked=!!r,y!=null&&typeof y!="function"&&typeof y!="symbol"&&typeof y!="boolean"&&(e.name=y),Uo(e)}function qo(e,t,l){t==="number"&&Ja(e.ownerDocument)===e||e.defaultValue===""+l||(e.defaultValue=""+l)}function Kl(e,t,l,r){if(e=e.options,t){t={};for(var c=0;c"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),Fo=!1;if(Rn)try{var Fi={};Object.defineProperty(Fi,"passive",{get:function(){Fo=!0}}),window.addEventListener("test",Fi,Fi),window.removeEventListener("test",Fi,Fi)}catch{Fo=!1}var Kn=null,Xo=null,Pa=null;function Af(){if(Pa)return Pa;var e,t=Xo,l=t.length,r,c="value"in Kn?Kn.value:Kn.textContent,f=c.length;for(e=0;e=Ki),Df=" ",Mf=!1;function jf(e,t){switch(e){case"keyup":return Jy.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function Lf(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var Wl=!1;function Py(e,t){switch(e){case"compositionend":return Lf(t);case"keypress":return t.which!==32?null:(Mf=!0,Df);case"textInput":return e=t.data,e===Df&&Mf?null:e;default:return null}}function eb(e,t){if(Wl)return e==="compositionend"||!Jo&&jf(e,t)?(e=Af(),Pa=Xo=Kn=null,Wl=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:l,offset:t-e};e=r}e:{for(;l;){if(l.nextSibling){l=l.nextSibling;break e}l=l.parentNode}l=void 0}l=Yf(l)}}function Xf(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Xf(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Qf(e){e=e!=null&&e.ownerDocument!=null&&e.ownerDocument.defaultView!=null?e.ownerDocument.defaultView:window;for(var t=Ja(e.document);t instanceof e.HTMLIFrameElement;){try{var l=typeof t.contentWindow.location.href=="string"}catch{l=!1}if(l)e=t.contentWindow;else break;t=Ja(e.document)}return t}function es(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}var sb=Rn&&"documentMode"in document&&11>=document.documentMode,Pl=null,ts=null,Wi=null,ns=!1;function Kf(e,t,l){var r=l.window===l?l.document:l.nodeType===9?l:l.ownerDocument;ns||Pl==null||Pl!==Ja(r)||(r=Pl,"selectionStart"in r&&es(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),Wi&&Ji(Wi,r)||(Wi=r,r=Xr(ts,"onSelect"),0>=y,c-=y,Sn=1<<32-be(t)+c|l<Ne?(je=ge,ge=null):je=ge.sibling;var He=M(N,ge,O[Ne],V);if(He===null){ge===null&&(ge=je);break}e&&ge&&He.alternate===null&&t(N,ge),A=f(He,A,Ne),qe===null?xe=He:qe.sibling=He,qe=He,ge=je}if(Ne===O.length)return l(N,ge),Ue&&Cn(N,Ne),xe;if(ge===null){for(;NeNe?(je=ge,ge=null):je=ge.sibling;var gl=M(N,ge,He.value,V);if(gl===null){ge===null&&(ge=je);break}e&&ge&&gl.alternate===null&&t(N,ge),A=f(gl,A,Ne),qe===null?xe=gl:qe.sibling=gl,qe=gl,ge=je}if(He.done)return l(N,ge),Ue&&Cn(N,Ne),xe;if(ge===null){for(;!He.done;Ne++,He=O.next())He=Y(N,He.value,V),He!==null&&(A=f(He,A,Ne),qe===null?xe=He:qe.sibling=He,qe=He);return Ue&&Cn(N,Ne),xe}for(ge=r(ge);!He.done;Ne++,He=O.next())He=U(ge,N,Ne,He.value,V),He!==null&&(e&&He.alternate!==null&&ge.delete(He.key===null?Ne:He.key),A=f(He,A,Ne),qe===null?xe=He:qe.sibling=He,qe=He);return e&&ge.forEach(function(N0){return t(N,N0)}),Ue&&Cn(N,Ne),xe}function Je(N,A,O,V){if(typeof O=="object"&&O!==null&&O.type===I&&O.key===null&&(O=O.props.children),typeof O=="object"&&O!==null){switch(O.$$typeof){case S:e:{for(var xe=O.key;A!==null;){if(A.key===xe){if(xe=O.type,xe===I){if(A.tag===7){l(N,A.sibling),V=c(A,O.props.children),V.return=N,N=V;break e}}else if(A.elementType===xe||typeof xe=="object"&&xe!==null&&xe.$$typeof===ue&&Dl(xe)===A.type){l(N,A.sibling),V=c(A,O.props),ia(V,O),V.return=N,N=V;break e}l(N,A);break}else t(N,A);A=A.sibling}O.type===I?(V=Nl(O.props.children,N.mode,V,O.key),V.return=N,N=V):(V=ur(O.type,O.key,O.props,null,N.mode,V),ia(V,O),V.return=N,N=V)}return y(N);case j:e:{for(xe=O.key;A!==null;){if(A.key===xe)if(A.tag===4&&A.stateNode.containerInfo===O.containerInfo&&A.stateNode.implementation===O.implementation){l(N,A.sibling),V=c(A,O.children||[]),V.return=N,N=V;break e}else{l(N,A);break}else t(N,A);A=A.sibling}V=us(O,N.mode,V),V.return=N,N=V}return y(N);case ue:return O=Dl(O),Je(N,A,O,V)}if($(O))return he(N,A,O,V);if(Z(O)){if(xe=Z(O),typeof xe!="function")throw Error(o(150));return O=xe.call(O),ve(N,A,O,V)}if(typeof O.then=="function")return Je(N,A,gr(O),V);if(O.$$typeof===B)return Je(N,A,dr(N,O),V);yr(N,O)}return typeof O=="string"&&O!==""||typeof O=="number"||typeof O=="bigint"?(O=""+O,A!==null&&A.tag===6?(l(N,A.sibling),V=c(A,O),V.return=N,N=V):(l(N,A),V=ss(O,N.mode,V),V.return=N,N=V),y(N)):l(N,A)}return function(N,A,O,V){try{la=0;var xe=Je(N,A,O,V);return ci=null,xe}catch(ge){if(ge===ui||ge===pr)throw ge;var qe=Qt(29,ge,null,N.mode);return qe.lanes=V,qe.return=N,qe}}}var jl=yd(!0),bd=yd(!1),Pn=!1;function Ss(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,lanes:0,hiddenCallbacks:null},callbacks:null}}function ks(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,callbacks:null})}function el(e){return{lane:e,tag:0,payload:null,callback:null,next:null}}function tl(e,t,l){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,(Ve&2)!==0){var c=r.pending;return c===null?t.next=t:(t.next=c.next,c.next=t),r.pending=t,t=sr(e),td(e,null,l),t}return or(e,r,t,l),sr(e)}function aa(e,t,l){if(t=t.updateQueue,t!==null&&(t=t.shared,(l&4194048)!==0)){var r=t.lanes;r&=e.pendingLanes,l|=r,t.lanes=l,uf(e,l)}}function ws(e,t){var l=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,l===r)){var c=null,f=null;if(l=l.firstBaseUpdate,l!==null){do{var y={lane:l.lane,tag:l.tag,payload:l.payload,callback:null,next:null};f===null?c=f=y:f=f.next=y,l=l.next}while(l!==null);f===null?c=f=t:f=f.next=t}else c=f=t;l={baseState:r.baseState,firstBaseUpdate:c,lastBaseUpdate:f,shared:r.shared,callbacks:r.callbacks},e.updateQueue=l;return}e=l.lastBaseUpdate,e===null?l.firstBaseUpdate=t:e.next=t,l.lastBaseUpdate=t}var Ts=!1;function ra(){if(Ts){var e=si;if(e!==null)throw e}}function oa(e,t,l,r){Ts=!1;var c=e.updateQueue;Pn=!1;var f=c.firstBaseUpdate,y=c.lastBaseUpdate,x=c.shared.pending;if(x!==null){c.shared.pending=null;var E=x,C=E.next;E.next=null,y===null?f=C:y.next=C,y=E;var H=e.alternate;H!==null&&(H=H.updateQueue,x=H.lastBaseUpdate,x!==y&&(x===null?H.firstBaseUpdate=C:x.next=C,H.lastBaseUpdate=E))}if(f!==null){var Y=c.baseState;y=0,H=C=E=null,x=f;do{var M=x.lane&-536870913,U=M!==x.lane;if(U?(Me&M)===M:(r&M)===M){M!==0&&M===oi&&(Ts=!0),H!==null&&(H=H.next={lane:0,tag:x.tag,payload:x.payload,callback:null,next:null});e:{var he=e,ve=x;M=t;var Je=l;switch(ve.tag){case 1:if(he=ve.payload,typeof he=="function"){Y=he.call(Je,Y,M);break e}Y=he;break e;case 3:he.flags=he.flags&-65537|128;case 0:if(he=ve.payload,M=typeof he=="function"?he.call(Je,Y,M):he,M==null)break e;Y=b({},Y,M);break e;case 2:Pn=!0}}M=x.callback,M!==null&&(e.flags|=64,U&&(e.flags|=8192),U=c.callbacks,U===null?c.callbacks=[M]:U.push(M))}else U={lane:M,tag:x.tag,payload:x.payload,callback:x.callback,next:null},H===null?(C=H=U,E=Y):H=H.next=U,y|=M;if(x=x.next,x===null){if(x=c.shared.pending,x===null)break;U=x,x=U.next,U.next=null,c.lastBaseUpdate=U,c.shared.pending=null}}while(!0);H===null&&(E=Y),c.baseState=E,c.firstBaseUpdate=C,c.lastBaseUpdate=H,f===null&&(c.shared.lanes=0),rl|=y,e.lanes=y,e.memoizedState=Y}}function xd(e,t){if(typeof e!="function")throw Error(o(191,e));e.call(t)}function vd(e,t){var l=e.callbacks;if(l!==null)for(e.callbacks=null,e=0;ef?f:8;var y=R.T,x={};R.T=x,Gs(e,!1,t,l);try{var E=c(),C=R.S;if(C!==null&&C(x,E),E!==null&&typeof E=="object"&&typeof E.then=="function"){var H=yb(E,r);ca(e,t,H,Wt(e))}else ca(e,t,r,Wt(e))}catch(Y){ca(e,t,{then:function(){},status:"rejected",reason:Y},Wt())}finally{K.p=f,y!==null&&x.types!==null&&(y.types=x.types),R.T=y}}function wb(){}function Hs(e,t,l,r){if(e.tag!==5)throw Error(o(476));var c=Wd(e).queue;Jd(e,c,t,fe,l===null?wb:function(){return Pd(e),l(r)})}function Wd(e){var t=e.memoizedState;if(t!==null)return t;t={memoizedState:fe,baseState:fe,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ln,lastRenderedState:fe},next:null};var l={};return t.next={memoizedState:l,baseState:l,baseQueue:null,queue:{pending:null,lanes:0,dispatch:null,lastRenderedReducer:Ln,lastRenderedState:l},next:null},e.memoizedState=t,e=e.alternate,e!==null&&(e.memoizedState=t),t}function Pd(e){var t=Wd(e);t.next===null&&(t=e.alternate.memoizedState),ca(e,t.next.queue,{},Wt())}function Vs(){return Nt(Aa)}function eh(){return dt().memoizedState}function th(){return dt().memoizedState}function Tb(e){for(var t=e.return;t!==null;){switch(t.tag){case 24:case 3:var l=Wt();e=el(l);var r=tl(t,e,l);r!==null&&(Vt(r,t,l),aa(r,t,l)),t={cache:ys()},e.payload=t;return}t=t.return}}function Eb(e,t,l){var r=Wt();l={lane:r,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null},Ar(e)?lh(t,l):(l=rs(e,t,l,r),l!==null&&(Vt(l,e,r),ih(l,t,r)))}function nh(e,t,l){var r=Wt();ca(e,t,l,r)}function ca(e,t,l,r){var c={lane:r,revertLane:0,gesture:null,action:l,hasEagerState:!1,eagerState:null,next:null};if(Ar(e))lh(t,c);else{var f=e.alternate;if(e.lanes===0&&(f===null||f.lanes===0)&&(f=t.lastRenderedReducer,f!==null))try{var y=t.lastRenderedState,x=f(y,l);if(c.hasEagerState=!0,c.eagerState=x,Xt(x,y))return or(e,t,c,0),et===null&&rr(),!1}catch{}if(l=rs(e,t,c,r),l!==null)return Vt(l,e,r),ih(l,t,r),!0}return!1}function Gs(e,t,l,r){if(r={lane:2,revertLane:Su(),gesture:null,action:r,hasEagerState:!1,eagerState:null,next:null},Ar(e)){if(t)throw Error(o(479))}else t=rs(e,l,r,2),t!==null&&Vt(t,e,2)}function Ar(e){var t=e.alternate;return e===Ae||t!==null&&t===Ae}function lh(e,t){di=vr=!0;var l=e.pending;l===null?t.next=t:(t.next=l.next,l.next=t),e.pending=t}function ih(e,t,l){if((l&4194048)!==0){var r=t.lanes;r&=e.pendingLanes,l|=r,t.lanes=l,uf(e,l)}}var fa={readContext:Nt,use:wr,useCallback:ut,useContext:ut,useEffect:ut,useImperativeHandle:ut,useLayoutEffect:ut,useInsertionEffect:ut,useMemo:ut,useReducer:ut,useRef:ut,useState:ut,useDebugValue:ut,useDeferredValue:ut,useTransition:ut,useSyncExternalStore:ut,useId:ut,useHostTransitionStatus:ut,useFormState:ut,useActionState:ut,useOptimistic:ut,useMemoCache:ut,useCacheRefresh:ut};fa.useEffectEvent=ut;var ah={readContext:Nt,use:wr,useCallback:function(e,t){return Dt().memoizedState=[e,t===void 0?null:t],e},useContext:Nt,useEffect:Vd,useImperativeHandle:function(e,t,l){l=l!=null?l.concat([e]):null,Er(4194308,4,Xd.bind(null,t,e),l)},useLayoutEffect:function(e,t){return Er(4194308,4,e,t)},useInsertionEffect:function(e,t){Er(4,2,e,t)},useMemo:function(e,t){var l=Dt();t=t===void 0?null:t;var r=e();if(Ll){oe(!0);try{e()}finally{oe(!1)}}return l.memoizedState=[r,t],r},useReducer:function(e,t,l){var r=Dt();if(l!==void 0){var c=l(t);if(Ll){oe(!0);try{l(t)}finally{oe(!1)}}}else c=t;return r.memoizedState=r.baseState=c,e={pending:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:c},r.queue=e,e=e.dispatch=Eb.bind(null,Ae,e),[r.memoizedState,e]},useRef:function(e){var t=Dt();return e={current:e},t.memoizedState=e},useState:function(e){e=Ls(e);var t=e.queue,l=nh.bind(null,Ae,t);return t.dispatch=l,[e.memoizedState,l]},useDebugValue:Is,useDeferredValue:function(e,t){var l=Dt();return qs(l,e,t)},useTransition:function(){var e=Ls(!1);return e=Jd.bind(null,Ae,e.queue,!0,!1),Dt().memoizedState=e,[!1,e]},useSyncExternalStore:function(e,t,l){var r=Ae,c=Dt();if(Ue){if(l===void 0)throw Error(o(407));l=l()}else{if(l=t(),et===null)throw Error(o(349));(Me&127)!==0||_d(r,t,l)}c.memoizedState=l;var f={value:l,getSnapshot:t};return c.queue=f,Vd(Nd.bind(null,r,f,e),[e]),r.flags|=2048,pi(9,{destroy:void 0},Ad.bind(null,r,f,l,t),null),l},useId:function(){var e=Dt(),t=et.identifierPrefix;if(Ue){var l=kn,r=Sn;l=(r&~(1<<32-be(r)-1)).toString(32)+l,t="_"+t+"R_"+l,l=Sr++,0<\/script>",f=f.removeChild(f.firstChild);break;case"select":f=typeof r.is=="string"?y.createElement("select",{is:r.is}):y.createElement("select"),r.multiple?f.multiple=!0:r.size&&(f.size=r.size);break;default:f=typeof r.is=="string"?y.createElement(c,{is:r.is}):y.createElement(c)}}f[_t]=t,f[Lt]=r;e:for(y=t.child;y!==null;){if(y.tag===5||y.tag===6)f.appendChild(y.stateNode);else if(y.tag!==4&&y.tag!==27&&y.child!==null){y.child.return=y,y=y.child;continue}if(y===t)break e;for(;y.sibling===null;){if(y.return===null||y.return===t)break e;y=y.return}y.sibling.return=y.return,y=y.sibling}t.stateNode=f;e:switch(Rt(f,c,r),c){case"button":case"input":case"select":case"textarea":r=!!r.autoFocus;break e;case"img":r=!0;break e;default:r=!1}r&&Un(t)}}return at(t),lu(t,t.type,e===null?null:e.memoizedProps,t.pendingProps,l),null;case 6:if(e&&t.stateNode!=null)e.memoizedProps!==r&&Un(t);else{if(typeof r!="string"&&t.stateNode===null)throw Error(o(166));if(e=Le.current,ai(t)){if(e=t.stateNode,l=t.memoizedProps,r=null,c=At,c!==null)switch(c.tag){case 27:case 5:r=c.memoizedProps}e[_t]=t,e=!!(e.nodeValue===l||r!==null&&r.suppressHydrationWarning===!0||Tp(e.nodeValue,l)),e||Jn(t,!0)}else e=Qr(e).createTextNode(r),e[_t]=t,t.stateNode=e}return at(t),null;case 31:if(l=t.memoizedState,e===null||e.memoizedState!==null){if(r=ai(t),l!==null){if(e===null){if(!r)throw Error(o(318));if(e=t.memoizedState,e=e!==null?e.dehydrated:null,!e)throw Error(o(557));e[_t]=t}else zl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;at(t),e=!1}else l=hs(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=l),e=!0;if(!e)return t.flags&256?($t(t),t):($t(t),null);if((t.flags&128)!==0)throw Error(o(558))}return at(t),null;case 13:if(r=t.memoizedState,e===null||e.memoizedState!==null&&e.memoizedState.dehydrated!==null){if(c=ai(t),r!==null&&r.dehydrated!==null){if(e===null){if(!c)throw Error(o(318));if(c=t.memoizedState,c=c!==null?c.dehydrated:null,!c)throw Error(o(317));c[_t]=t}else zl(),(t.flags&128)===0&&(t.memoizedState=null),t.flags|=4;at(t),c=!1}else c=hs(),e!==null&&e.memoizedState!==null&&(e.memoizedState.hydrationErrors=c),c=!0;if(!c)return t.flags&256?($t(t),t):($t(t),null)}return $t(t),(t.flags&128)!==0?(t.lanes=l,t):(l=r!==null,e=e!==null&&e.memoizedState!==null,l&&(r=t.child,c=null,r.alternate!==null&&r.alternate.memoizedState!==null&&r.alternate.memoizedState.cachePool!==null&&(c=r.alternate.memoizedState.cachePool.pool),f=null,r.memoizedState!==null&&r.memoizedState.cachePool!==null&&(f=r.memoizedState.cachePool.pool),f!==c&&(r.flags|=2048)),l!==e&&l&&(t.child.flags|=8192),Cr(t,t.updateQueue),at(t),null);case 4:return We(),e===null&&Eu(t.stateNode.containerInfo),at(t),null;case 10:return Mn(t.type),at(t),null;case 19:if(Se(ft),r=t.memoizedState,r===null)return at(t),null;if(c=(t.flags&128)!==0,f=r.rendering,f===null)if(c)ha(r,!1);else{if(ct!==0||e!==null&&(e.flags&128)!==0)for(e=t.child;e!==null;){if(f=xr(e),f!==null){for(t.flags|=128,ha(r,!1),e=f.updateQueue,t.updateQueue=e,Cr(t,e),t.subtreeFlags=0,e=l,l=t.child;l!==null;)nd(l,e),l=l.sibling;return T(ft,ft.current&1|2),Ue&&Cn(t,r.treeForkCount),t.child}e=e.sibling}r.tail!==null&&ie()>Br&&(t.flags|=128,c=!0,ha(r,!1),t.lanes=4194304)}else{if(!c)if(e=xr(f),e!==null){if(t.flags|=128,c=!0,e=e.updateQueue,t.updateQueue=e,Cr(t,e),ha(r,!0),r.tail===null&&r.tailMode==="hidden"&&!f.alternate&&!Ue)return at(t),null}else 2*ie()-r.renderingStartTime>Br&&l!==536870912&&(t.flags|=128,c=!0,ha(r,!1),t.lanes=4194304);r.isBackwards?(f.sibling=t.child,t.child=f):(e=r.last,e!==null?e.sibling=f:t.child=f,r.last=f)}return r.tail!==null?(e=r.tail,r.rendering=e,r.tail=e.sibling,r.renderingStartTime=ie(),e.sibling=null,l=ft.current,T(ft,c?l&1|2:l&1),Ue&&Cn(t,r.treeForkCount),e):(at(t),null);case 22:case 23:return $t(t),_s(),r=t.memoizedState!==null,e!==null?e.memoizedState!==null!==r&&(t.flags|=8192):r&&(t.flags|=8192),r?(l&536870912)!==0&&(t.flags&128)===0&&(at(t),t.subtreeFlags&6&&(t.flags|=8192)):at(t),l=t.updateQueue,l!==null&&Cr(t,l.retryQueue),l=null,e!==null&&e.memoizedState!==null&&e.memoizedState.cachePool!==null&&(l=e.memoizedState.cachePool.pool),r=null,t.memoizedState!==null&&t.memoizedState.cachePool!==null&&(r=t.memoizedState.cachePool.pool),r!==l&&(t.flags|=2048),e!==null&&Se(Cl),null;case 24:return l=null,e!==null&&(l=e.memoizedState.cache),t.memoizedState.cache!==l&&(t.flags|=2048),Mn(pt),at(t),null;case 25:return null;case 30:return null}throw Error(o(156,t.tag))}function Rb(e,t){switch(fs(t),t.tag){case 1:return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Mn(pt),We(),e=t.flags,(e&65536)!==0&&(e&128)===0?(t.flags=e&-65537|128,t):null;case 26:case 27:case 5:return Pe(t),null;case 31:if(t.memoizedState!==null){if($t(t),t.alternate===null)throw Error(o(340));zl()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 13:if($t(t),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(o(340));zl()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return Se(ft),null;case 4:return We(),null;case 10:return Mn(t.type),null;case 22:case 23:return $t(t),_s(),e!==null&&Se(Cl),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 24:return Mn(pt),null;case 25:return null;default:return null}}function zh(e,t){switch(fs(t),t.tag){case 3:Mn(pt),We();break;case 26:case 27:case 5:Pe(t);break;case 4:We();break;case 31:t.memoizedState!==null&&$t(t);break;case 13:$t(t);break;case 19:Se(ft);break;case 10:Mn(t.type);break;case 22:case 23:$t(t),_s(),e!==null&&Se(Cl);break;case 24:Mn(pt)}}function pa(e,t){try{var l=t.updateQueue,r=l!==null?l.lastEffect:null;if(r!==null){var c=r.next;l=c;do{if((l.tag&e)===e){r=void 0;var f=l.create,y=l.inst;r=f(),y.destroy=r}l=l.next}while(l!==c)}}catch(x){Qe(t,t.return,x)}}function il(e,t,l){try{var r=t.updateQueue,c=r!==null?r.lastEffect:null;if(c!==null){var f=c.next;r=f;do{if((r.tag&e)===e){var y=r.inst,x=y.destroy;if(x!==void 0){y.destroy=void 0,c=t;var E=l,C=x;try{C()}catch(H){Qe(c,E,H)}}}r=r.next}while(r!==f)}}catch(H){Qe(t,t.return,H)}}function Rh(e){var t=e.updateQueue;if(t!==null){var l=e.stateNode;try{vd(t,l)}catch(r){Qe(e,e.return,r)}}}function Oh(e,t,l){l.props=Bl(e.type,e.memoizedProps),l.state=e.memoizedState;try{l.componentWillUnmount()}catch(r){Qe(e,t,r)}}function ma(e,t){try{var l=e.ref;if(l!==null){switch(e.tag){case 26:case 27:case 5:var r=e.stateNode;break;case 30:r=e.stateNode;break;default:r=e.stateNode}typeof l=="function"?e.refCleanup=l(r):l.current=r}}catch(c){Qe(e,t,c)}}function wn(e,t){var l=e.ref,r=e.refCleanup;if(l!==null)if(typeof r=="function")try{r()}catch(c){Qe(e,t,c)}finally{e.refCleanup=null,e=e.alternate,e!=null&&(e.refCleanup=null)}else if(typeof l=="function")try{l(null)}catch(c){Qe(e,t,c)}else l.current=null}function Ch(e){var t=e.type,l=e.memoizedProps,r=e.stateNode;try{e:switch(t){case"button":case"input":case"select":case"textarea":l.autoFocus&&r.focus();break e;case"img":l.src?r.src=l.src:l.srcSet&&(r.srcset=l.srcSet)}}catch(c){Qe(e,e.return,c)}}function iu(e,t,l){try{var r=e.stateNode;Wb(r,e.type,l,t),r[Lt]=t}catch(c){Qe(e,e.return,c)}}function Dh(e){return e.tag===5||e.tag===3||e.tag===26||e.tag===27&&fl(e.type)||e.tag===4}function au(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Dh(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.tag===27&&fl(e.type)||e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function ru(e,t,l){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?(l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l).insertBefore(e,t):(t=l.nodeType===9?l.body:l.nodeName==="HTML"?l.ownerDocument.body:l,t.appendChild(e),l=l._reactRootContainer,l!=null||t.onclick!==null||(t.onclick=zn));else if(r!==4&&(r===27&&fl(e.type)&&(l=e.stateNode,t=null),e=e.child,e!==null))for(ru(e,t,l),e=e.sibling;e!==null;)ru(e,t,l),e=e.sibling}function Dr(e,t,l){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?l.insertBefore(e,t):l.appendChild(e);else if(r!==4&&(r===27&&fl(e.type)&&(l=e.stateNode),e=e.child,e!==null))for(Dr(e,t,l),e=e.sibling;e!==null;)Dr(e,t,l),e=e.sibling}function Mh(e){var t=e.stateNode,l=e.memoizedProps;try{for(var r=e.type,c=t.attributes;c.length;)t.removeAttributeNode(c[0]);Rt(t,r,l),t[_t]=e,t[Lt]=l}catch(f){Qe(e,e.return,f)}}var In=!1,yt=!1,ou=!1,jh=typeof WeakSet=="function"?WeakSet:Set,wt=null;function Ob(e,t){if(e=e.containerInfo,Nu=eo,e=Qf(e),es(e)){if("selectionStart"in e)var l={start:e.selectionStart,end:e.selectionEnd};else e:{l=(l=e.ownerDocument)&&l.defaultView||window;var r=l.getSelection&&l.getSelection();if(r&&r.rangeCount!==0){l=r.anchorNode;var c=r.anchorOffset,f=r.focusNode;r=r.focusOffset;try{l.nodeType,f.nodeType}catch{l=null;break e}var y=0,x=-1,E=-1,C=0,H=0,Y=e,M=null;t:for(;;){for(var U;Y!==l||c!==0&&Y.nodeType!==3||(x=y+c),Y!==f||r!==0&&Y.nodeType!==3||(E=y+r),Y.nodeType===3&&(y+=Y.nodeValue.length),(U=Y.firstChild)!==null;)M=Y,Y=U;for(;;){if(Y===e)break t;if(M===l&&++C===c&&(x=y),M===f&&++H===r&&(E=y),(U=Y.nextSibling)!==null)break;Y=M,M=Y.parentNode}Y=U}l=x===-1||E===-1?null:{start:x,end:E}}else l=null}l=l||{start:0,end:0}}else l=null;for(zu={focusedElem:e,selectionRange:l},eo=!1,wt=t;wt!==null;)if(t=wt,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,wt=e;else for(;wt!==null;){switch(t=wt,f=t.alternate,e=t.flags,t.tag){case 0:if((e&4)!==0&&(e=t.updateQueue,e=e!==null?e.events:null,e!==null))for(l=0;l title"))),Rt(f,r,l),f[_t]=e,kt(f),r=f;break e;case"link":var y=Hp("link","href",c).get(r+(l.href||""));if(y){for(var x=0;xJe&&(y=Je,Je=ve,ve=y);var N=Ff(x,ve),A=Ff(x,Je);if(N&&A&&(U.rangeCount!==1||U.anchorNode!==N.node||U.anchorOffset!==N.offset||U.focusNode!==A.node||U.focusOffset!==A.offset)){var O=Y.createRange();O.setStart(N.node,N.offset),U.removeAllRanges(),ve>Je?(U.addRange(O),U.extend(A.node,A.offset)):(O.setEnd(A.node,A.offset),U.addRange(O))}}}}for(Y=[],U=x;U=U.parentNode;)U.nodeType===1&&Y.push({element:U,left:U.scrollLeft,top:U.scrollTop});for(typeof x.focus=="function"&&x.focus(),x=0;xl?32:l,R.T=null,l=pu,pu=null;var f=sl,y=Yn;if(vt=0,xi=sl=null,Yn=0,(Ve&6)!==0)throw Error(o(331));var x=Ve;if(Ve|=4,Xh(f.current),Gh(f,f.current,y,l),Ve=x,Sa(0,!1),se&&typeof se.onPostCommitFiberRoot=="function")try{se.onPostCommitFiberRoot(Q,f)}catch{}return!0}finally{K.p=c,R.T=r,cp(e,t)}}function dp(e,t,l){t=rn(l,t),t=Qs(e.stateNode,t,2),e=tl(e,t,2),e!==null&&(Hi(e,2),Tn(e))}function Qe(e,t,l){if(e.tag===3)dp(e,e,l);else for(;t!==null;){if(t.tag===3){dp(t,e,l);break}else if(t.tag===1){var r=t.stateNode;if(typeof t.type.getDerivedStateFromError=="function"||typeof r.componentDidCatch=="function"&&(ol===null||!ol.has(r))){e=rn(l,e),l=hh(2),r=tl(t,l,2),r!==null&&(ph(l,r,t,e),Hi(r,2),Tn(r));break}}t=t.return}}function bu(e,t,l){var r=e.pingCache;if(r===null){r=e.pingCache=new Mb;var c=new Set;r.set(t,c)}else c=r.get(t),c===void 0&&(c=new Set,r.set(t,c));c.has(l)||(cu=!0,c.add(l),e=Ib.bind(null,e,t,l),t.then(e,e))}function Ib(e,t,l){var r=e.pingCache;r!==null&&r.delete(t),e.pingedLanes|=e.suspendedLanes&l,e.warmLanes&=~l,et===e&&(Me&l)===l&&(ct===4||ct===3&&(Me&62914560)===Me&&300>ie()-Lr?(Ve&2)===0&&vi(e,0):fu|=l,bi===Me&&(bi=0)),Tn(e)}function hp(e,t){t===0&&(t=of()),e=Al(e,t),e!==null&&(Hi(e,t),Tn(e))}function qb(e){var t=e.memoizedState,l=0;t!==null&&(l=t.retryLane),hp(e,l)}function Hb(e,t){var l=0;switch(e.tag){case 31:case 13:var r=e.stateNode,c=e.memoizedState;c!==null&&(l=c.retryLane);break;case 19:r=e.stateNode;break;case 22:r=e.stateNode._retryCache;break;default:throw Error(o(314))}r!==null&&r.delete(t),hp(e,l)}function Vb(e,t){return st(e,t)}var Gr=null,ki=null,xu=!1,Yr=!1,vu=!1,cl=0;function Tn(e){e!==ki&&e.next===null&&(ki===null?Gr=ki=e:ki=ki.next=e),Yr=!0,xu||(xu=!0,Yb())}function Sa(e,t){if(!vu&&Yr){vu=!0;do for(var l=!1,r=Gr;r!==null;){if(e!==0){var c=r.pendingLanes;if(c===0)var f=0;else{var y=r.suspendedLanes,x=r.pingedLanes;f=(1<<31-be(42|e)+1)-1,f&=c&~(y&~x),f=f&201326741?f&201326741|1:f?f|2:0}f!==0&&(l=!0,yp(r,f))}else f=Me,f=Ka(r,r===et?f:0,r.cancelPendingCommit!==null||r.timeoutHandle!==-1),(f&3)===0||qi(r,f)||(l=!0,yp(r,f));r=r.next}while(l);vu=!1}}function Gb(){pp()}function pp(){Yr=xu=!1;var e=0;cl!==0&&e0()&&(e=cl);for(var t=ie(),l=null,r=Gr;r!==null;){var c=r.next,f=mp(r,t);f===0?(r.next=null,l===null?Gr=c:l.next=c,c===null&&(ki=l)):(l=r,(e!==0||(f&3)!==0)&&(Yr=!0)),r=c}vt!==0&&vt!==5||Sa(e),cl!==0&&(cl=0)}function mp(e,t){for(var l=e.suspendedLanes,r=e.pingedLanes,c=e.expirationTimes,f=e.pendingLanes&-62914561;0x)break;var H=E.transferSize,Y=E.initiatorType;H&&Ep(Y)&&(E=E.responseEnd,y+=H*(E"u"?null:document;function Bp(e,t,l){var r=wi;if(r&&typeof t=="string"&&t){var c=ln(t);c='link[rel="'+e+'"][href="'+c+'"]',typeof l=="string"&&(c+='[crossorigin="'+l+'"]'),Lp.has(c)||(Lp.add(c),e={rel:e,crossOrigin:l,href:t},r.querySelector(c)===null&&(t=r.createElement("link"),Rt(t,"link",e),kt(t),r.head.appendChild(t)))}}function u0(e){Fn.D(e),Bp("dns-prefetch",e,null)}function c0(e,t){Fn.C(e,t),Bp("preconnect",e,t)}function f0(e,t,l){Fn.L(e,t,l);var r=wi;if(r&&e&&t){var c='link[rel="preload"][as="'+ln(t)+'"]';t==="image"&&l&&l.imageSrcSet?(c+='[imagesrcset="'+ln(l.imageSrcSet)+'"]',typeof l.imageSizes=="string"&&(c+='[imagesizes="'+ln(l.imageSizes)+'"]')):c+='[href="'+ln(e)+'"]';var f=c;switch(t){case"style":f=Ti(e);break;case"script":f=Ei(e)}dn.has(f)||(e=b({rel:"preload",href:t==="image"&&l&&l.imageSrcSet?void 0:e,as:t},l),dn.set(f,e),r.querySelector(c)!==null||t==="style"&&r.querySelector(Ea(f))||t==="script"&&r.querySelector(_a(f))||(t=r.createElement("link"),Rt(t,"link",e),kt(t),r.head.appendChild(t)))}}function d0(e,t){Fn.m(e,t);var l=wi;if(l&&e){var r=t&&typeof t.as=="string"?t.as:"script",c='link[rel="modulepreload"][as="'+ln(r)+'"][href="'+ln(e)+'"]',f=c;switch(r){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":f=Ei(e)}if(!dn.has(f)&&(e=b({rel:"modulepreload",href:e},t),dn.set(f,e),l.querySelector(c)===null)){switch(r){case"audioworklet":case"paintworklet":case"serviceworker":case"sharedworker":case"worker":case"script":if(l.querySelector(_a(f)))return}r=l.createElement("link"),Rt(r,"link",e),kt(r),l.head.appendChild(r)}}}function h0(e,t,l){Fn.S(e,t,l);var r=wi;if(r&&e){var c=Xl(r).hoistableStyles,f=Ti(e);t=t||"default";var y=c.get(f);if(!y){var x={loading:0,preload:null};if(y=r.querySelector(Ea(f)))x.loading=5;else{e=b({rel:"stylesheet",href:e,"data-precedence":t},l),(l=dn.get(f))&&Lu(e,l);var E=y=r.createElement("link");kt(E),Rt(E,"link",e),E._p=new Promise(function(C,H){E.onload=C,E.onerror=H}),E.addEventListener("load",function(){x.loading|=1}),E.addEventListener("error",function(){x.loading|=2}),x.loading|=4,$r(y,t,r)}y={type:"stylesheet",instance:y,count:1,state:x},c.set(f,y)}}}function p0(e,t){Fn.X(e,t);var l=wi;if(l&&e){var r=Xl(l).hoistableScripts,c=Ei(e),f=r.get(c);f||(f=l.querySelector(_a(c)),f||(e=b({src:e,async:!0},t),(t=dn.get(c))&&Bu(e,t),f=l.createElement("script"),kt(f),Rt(f,"link",e),l.head.appendChild(f)),f={type:"script",instance:f,count:1,state:null},r.set(c,f))}}function m0(e,t){Fn.M(e,t);var l=wi;if(l&&e){var r=Xl(l).hoistableScripts,c=Ei(e),f=r.get(c);f||(f=l.querySelector(_a(c)),f||(e=b({src:e,async:!0,type:"module"},t),(t=dn.get(c))&&Bu(e,t),f=l.createElement("script"),kt(f),Rt(f,"link",e),l.head.appendChild(f)),f={type:"script",instance:f,count:1,state:null},r.set(c,f))}}function Up(e,t,l,r){var c=(c=Le.current)?Kr(c):null;if(!c)throw Error(o(446));switch(e){case"meta":case"title":return null;case"style":return typeof l.precedence=="string"&&typeof l.href=="string"?(t=Ti(l.href),l=Xl(c).hoistableStyles,r=l.get(t),r||(r={type:"style",instance:null,count:0,state:null},l.set(t,r)),r):{type:"void",instance:null,count:0,state:null};case"link":if(l.rel==="stylesheet"&&typeof l.href=="string"&&typeof l.precedence=="string"){e=Ti(l.href);var f=Xl(c).hoistableStyles,y=f.get(e);if(y||(c=c.ownerDocument||c,y={type:"stylesheet",instance:null,count:0,state:{loading:0,preload:null}},f.set(e,y),(f=c.querySelector(Ea(e)))&&!f._p&&(y.instance=f,y.state.loading=5),dn.has(e)||(l={rel:"preload",as:"style",href:l.href,crossOrigin:l.crossOrigin,integrity:l.integrity,media:l.media,hrefLang:l.hrefLang,referrerPolicy:l.referrerPolicy},dn.set(e,l),f||g0(c,e,l,y.state))),t&&r===null)throw Error(o(528,""));return y}if(t&&r!==null)throw Error(o(529,""));return null;case"script":return t=l.async,l=l.src,typeof l=="string"&&t&&typeof t!="function"&&typeof t!="symbol"?(t=Ei(l),l=Xl(c).hoistableScripts,r=l.get(t),r||(r={type:"script",instance:null,count:0,state:null},l.set(t,r)),r):{type:"void",instance:null,count:0,state:null};default:throw Error(o(444,e))}}function Ti(e){return'href="'+ln(e)+'"'}function Ea(e){return'link[rel="stylesheet"]['+e+"]"}function Ip(e){return b({},e,{"data-precedence":e.precedence,precedence:null})}function g0(e,t,l,r){e.querySelector('link[rel="preload"][as="style"]['+t+"]")?r.loading=1:(t=e.createElement("link"),r.preload=t,t.addEventListener("load",function(){return r.loading|=1}),t.addEventListener("error",function(){return r.loading|=2}),Rt(t,"link",l),kt(t),e.head.appendChild(t))}function Ei(e){return'[src="'+ln(e)+'"]'}function _a(e){return"script[async]"+e}function qp(e,t,l){if(t.count++,t.instance===null)switch(t.type){case"style":var r=e.querySelector('style[data-href~="'+ln(l.href)+'"]');if(r)return t.instance=r,kt(r),r;var c=b({},l,{"data-href":l.href,"data-precedence":l.precedence,href:null,precedence:null});return r=(e.ownerDocument||e).createElement("style"),kt(r),Rt(r,"style",c),$r(r,l.precedence,e),t.instance=r;case"stylesheet":c=Ti(l.href);var f=e.querySelector(Ea(c));if(f)return t.state.loading|=4,t.instance=f,kt(f),f;r=Ip(l),(c=dn.get(c))&&Lu(r,c),f=(e.ownerDocument||e).createElement("link"),kt(f);var y=f;return y._p=new Promise(function(x,E){y.onload=x,y.onerror=E}),Rt(f,"link",r),t.state.loading|=4,$r(f,l.precedence,e),t.instance=f;case"script":return f=Ei(l.src),(c=e.querySelector(_a(f)))?(t.instance=c,kt(c),c):(r=l,(c=dn.get(f))&&(r=b({},l),Bu(r,c)),e=e.ownerDocument||e,c=e.createElement("script"),kt(c),Rt(c,"link",r),e.head.appendChild(c),t.instance=c);case"void":return null;default:throw Error(o(443,t.type))}else t.type==="stylesheet"&&(t.state.loading&4)===0&&(r=t.instance,t.state.loading|=4,$r(r,l.precedence,e));return t.instance}function $r(e,t,l){for(var r=l.querySelectorAll('link[rel="stylesheet"][data-precedence],style[data-precedence]'),c=r.length?r[r.length-1]:null,f=c,y=0;y title"):null)}function y0(e,t,l){if(l===1||t.itemProp!=null)return!1;switch(e){case"meta":case"title":return!0;case"style":if(typeof t.precedence!="string"||typeof t.href!="string"||t.href==="")break;return!0;case"link":if(typeof t.rel!="string"||typeof t.href!="string"||t.href===""||t.onLoad||t.onError)break;return t.rel==="stylesheet"?(e=t.disabled,typeof t.precedence=="string"&&e==null):!0;case"script":if(t.async&&typeof t.async!="function"&&typeof t.async!="symbol"&&!t.onLoad&&!t.onError&&t.src&&typeof t.src=="string")return!0}return!1}function Gp(e){return!(e.type==="stylesheet"&&(e.state.loading&3)===0)}function b0(e,t,l,r){if(l.type==="stylesheet"&&(typeof r.media!="string"||matchMedia(r.media).matches!==!1)&&(l.state.loading&4)===0){if(l.instance===null){var c=Ti(r.href),f=t.querySelector(Ea(c));if(f){t=f._p,t!==null&&typeof t=="object"&&typeof t.then=="function"&&(e.count++,e=Jr.bind(e),t.then(e,e)),l.state.loading|=4,l.instance=f,kt(f);return}f=t.ownerDocument||t,r=Ip(r),(c=dn.get(c))&&Lu(r,c),f=f.createElement("link"),kt(f);var y=f;y._p=new Promise(function(x,E){y.onload=x,y.onerror=E}),Rt(f,"link",r),l.instance=f}e.stylesheets===null&&(e.stylesheets=new Map),e.stylesheets.set(l,t),(t=l.state.preload)&&(l.state.loading&3)===0&&(e.count++,l=Jr.bind(e),t.addEventListener("load",l),t.addEventListener("error",l))}}var Uu=0;function x0(e,t){return e.stylesheets&&e.count===0&&Pr(e,e.stylesheets),0Uu?50:800)+t);return e.unsuspend=l,function(){e.unsuspend=null,clearTimeout(r),clearTimeout(c)}}:null}function Jr(){if(this.count--,this.count===0&&(this.imgCount===0||!this.waitingForImages)){if(this.stylesheets)Pr(this,this.stylesheets);else if(this.unsuspend){var e=this.unsuspend;this.unsuspend=null,e()}}}var Wr=null;function Pr(e,t){e.stylesheets=null,e.unsuspend!==null&&(e.count++,Wr=new Map,t.forEach(v0,e),Wr=null,Jr.call(e))}function v0(e,t){if(!(t.state.loading&4)){var l=Wr.get(e);if(l)var r=l.get(null);else{l=new Map,Wr.set(e,l);for(var c=e.querySelectorAll("link[data-precedence],style[data-precedence]"),f=0;f"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(a)}catch(n){console.error(n)}}return a(),Fu.exports=K0(),Fu.exports}var Z0=$0(),Mt=(a=>(a[a.FORWARD=0]="FORWARD",a[a.NEWEST_FIRST=1]="NEWEST_FIRST",a))(Mt||{});class J0 extends Ee{constructor(){super("avalanche.operator.Empty",[])}create(n){const i=globalThis.Object.create(this.messagePrototype);return n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posKu},{no:6,name:"run_id",kind:"scalar",T:9},{no:7,name:"workflow_selector",kind:"scalar",T:9}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.inputJson="",i.contextJson="",i.inputFiles=[],i.runId="",i.workflowSelector="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.pos["avalanche.operator.DescriptorPageOrder",Mt,"DESCRIPTOR_PAGE_ORDER_"]}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.pageToken="",i.afterSequence="0",i.pageSize=0,i.beforeSequence="0",i.nodeId="",i.order=0,n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.pos["avalanche.operator.DescriptorPageOrder",Mt,"DESCRIPTOR_PAGE_ORDER_"]}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.pageToken="",i.afterEventSequence="0",i.pageSize=0,i.beforeEventSequence="0",i.order=0,n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posbl}},{no:3,name:"node_types",kind:"map",K:9,V:{kind:"scalar",T:9}},{no:4,name:"display_names",kind:"map",K:9,V:{kind:"scalar",T:9}},{no:5,name:"agent_field_schemas_json",kind:"map",K:9,V:{kind:"scalar",T:9}},{no:6,name:"agent_instruction_lines",kind:"map",K:9,V:{kind:"scalar",T:9}}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.nodeIds=[],i.graph={},i.nodeTypes={},i.displayNames={},i.agentFieldSchemasJson={},i.agentInstructionLines={},n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posbl}},{no:5,name:"node_types",kind:"map",K:9,V:{kind:"scalar",T:9}},{no:6,name:"display_names",kind:"map",K:9,V:{kind:"scalar",T:9}},{no:7,name:"cron",kind:"scalar",T:9},{no:8,name:"next_run_at",kind:"scalar",T:1},{no:9,name:"last_run_at",kind:"scalar",T:1},{no:10,name:"workflow_id",kind:"scalar",T:9},{no:11,name:"display_name",kind:"scalar",T:9},{no:12,name:"root_alias",kind:"scalar",T:9},{no:13,name:"relative_file",kind:"scalar",T:9},{no:14,name:"builder_symbol",kind:"scalar",T:9},{no:15,name:"agent_node_ids",kind:"scalar",repeat:2,T:9},{no:16,name:"agent_metadata_json",kind:"map",K:9,V:{kind:"scalar",T:9}},{no:17,name:"webhook_path",kind:"scalar",T:9},{no:18,name:"webhook_url",kind:"scalar",T:9},{no:19,name:"webhook_active",kind:"scalar",T:8}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.name="",i.filePath="",i.nodeIds=[],i.graph={},i.nodeTypes={},i.displayNames={},i.cron="",i.nextRunAt=0,i.lastRunAt=0,i.workflowId="",i.displayName="",i.rootAlias="",i.relativeFile="",i.builderSymbol="",i.agentNodeIds=[],i.agentMetadataJson={},i.webhookPath="",i.webhookUrl="",i.webhookActive=!1,n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.pos$u},{no:5,name:"scan_targets",kind:"message",repeat:2,T:()=>Ju},{no:6,name:"diagnostics",kind:"message",repeat:2,T:()=>Zu}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.operatorInstanceId="",i.asOfSequence="0",i.revision="0",i.workflows=[],i.scanTargets=[],i.diagnostics=[],n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posWu}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.valueJson="",i.files=[],n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posPu}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.status="",i.revision="0",i.available=!1,i.complete=!1,i.eventCount="0",i.sizeBytes="0",i.latestEventSequence="0",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posOi},{no:8,name:"revision",kind:"scalar",T:4},{no:9,name:"event_page_token",kind:"scalar",T:9},{no:10,name:"error",kind:"scalar",opt:!0,T:9},{no:11,name:"running_elapsed_seconds",kind:"scalar",opt:!0,T:1}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.nodeId="",i.name="",i.nodeType="",i.status="",i.startedAt=0,i.endedAt=0,i.revision="0",i.eventPageToken="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posXn},{no:4,name:"nodes",kind:"message",repeat:2,T:()=>Ci},{no:5,name:"latest_log_sequence",kind:"scalar",T:4},{no:6,name:"log_page_token",kind:"scalar",T:9},{no:7,name:"topology",kind:"message",T:()=>Ri}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.operatorInstanceId="",i.asOfSequence="0",i.nodes=[],i.latestLogSequence="0",i.logPageToken="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posXn},{no:4,name:"next_page_token",kind:"scalar",T:9}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.operatorInstanceId="",i.asOfSequence="0",i.runs=[],i.nextPageToken="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posDi},{no:4,name:"next_page_token",kind:"scalar",T:9}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.operatorInstanceId="",i.asOfSequence="0",i.logs=[],i.nextPageToken="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posMi},{no:6,name:"next_page_token",kind:"scalar",T:9}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.operatorInstanceId="",i.asOfSequence="0",i.runId="",i.nodeId="",i.events=[],i.nextPageToken="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posXn},{no:2,name:"nodes",kind:"message",repeat:2,T:()=>Ci},{no:3,name:"topology",kind:"message",T:()=>Ri}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.nodes=[],n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posDi}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.runId="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posMi}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.runId="",i.nodeId="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posOi}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.runId="",i.nodeId="",n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posxo}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posec},{no:3,name:"run_status_changed",kind:"message",oneof:"change",T:()=>tc},{no:4,name:"node_status_changed",kind:"message",oneof:"change",T:()=>nc},{no:5,name:"log_appended",kind:"message",oneof:"change",T:()=>lc},{no:6,name:"agent_event_appended",kind:"message",oneof:"change",T:()=>ic},{no:7,name:"trace_finalized",kind:"message",oneof:"change",T:()=>ac},{no:8,name:"catalog_replaced",kind:"message",oneof:"change",T:()=>rc}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.sequence="0",i.change={oneofKind:void 0},n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.posoc},{no:3,name:"reset_required",kind:"message",oneof:"payload",T:()=>sc}])}create(n){const i=globalThis.Object.create(this.messagePrototype);return i.operatorInstanceId="",i.payload={oneofKind:void 0},n!==void 0&&_e(this,i,n),i}internalBinaryRead(n,i,o,u){let s=u??this.create(),d=n.pos+i;for(;n.pos=o1)throw new Error("Run baseline exceeds the page hydration budget");if(u.has(s))throw new Error("Run summary pagination made no progress");u.add(s);const g=await this.client.listRunSummaries({workflowSelector:"",pageSize:100,pageToken:s},n?{abort:n}:void 0).response;if(!d)d=g.operatorInstanceId,h=g.asOfSequence;else if(g.operatorInstanceId!==d||g.asOfSequence!==h)throw new Error("Run baseline changed while loading pages");for(const b of g.runs){const k=new TextEncoder().encode(JSON.stringify(b)).byteLength;if(o.length>=s1||m+k>u1)throw new Error("Run baseline exceeds the hydration budget");o.push(b),m+=k}s=g.nextPageToken}while(s);const p=await this.getCatalog(n);if(i.operatorInstanceId!==d||p.operatorInstanceId!==d||i.revision!==p.revision||BigInt(i.asOfSequence)>BigInt(h)||BigInt(p.asOfSequence)=BigInt(i)))throw new Error(`${d} pagination made no progress`)}const fg=(...a)=>a.filter((n,i,o)=>!!n&&n.trim()!==""&&o.indexOf(n)===i).join(" ").trim();const f1=a=>a.replace(/([a-z0-9])([A-Z])/g,"$1-$2").toLowerCase();const d1=a=>a.replace(/^([A-Z])|[\s-_]+(\w)/g,(n,i,o)=>o?o.toUpperCase():i.toLowerCase());const fm=a=>{const n=d1(a);return n.charAt(0).toUpperCase()+n.slice(1)};var cc={xmlns:"http://www.w3.org/2000/svg",width:24,height:24,viewBox:"0 0 24 24",fill:"none",stroke:"currentColor",strokeWidth:2,strokeLinecap:"round",strokeLinejoin:"round"};const h1=a=>{for(const n in a)if(n.startsWith("aria-")||n==="role"||n==="title")return!0;return!1},p1=L.createContext({}),m1=()=>L.useContext(p1),g1=L.forwardRef(({color:a,size:n,strokeWidth:i,absoluteStrokeWidth:o,className:u="",children:s,iconNode:d,...h},m)=>{const{size:p=24,strokeWidth:g=2,absoluteStrokeWidth:b=!1,color:k="currentColor",className:S=""}=m1()??{},j=o??b?Number(i??g)*24/Number(n??p):i??g;return L.createElement("svg",{ref:m,...cc,width:n??p??cc.width,height:n??p??cc.height,stroke:a??k,strokeWidth:j,className:fg("lucide",S,u),...!s&&!h1(h)&&{"aria-hidden":"true"},...h},[...d.map(([I,X])=>L.createElement(I,X)),...Array.isArray(s)?s:[s]])});const No=(a,n)=>{const i=L.forwardRef(({className:o,...u},s)=>L.createElement(g1,{ref:s,iconNode:n,className:fg(`lucide-${f1(fm(a))}`,`lucide-${a}`,o),...u}));return i.displayName=fm(a),i};const y1=[["path",{d:"M20 6 9 17l-5-5",key:"1gmf2c"}]],b1=No("check",y1);const x1=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M9 3v18",key:"fh3hqa"}],["path",{d:"m16 15-3-3 3-3",key:"14y99z"}]],v1=No("panel-left-close",x1);const S1=[["rect",{width:"18",height:"18",x:"3",y:"3",rx:"2",key:"afitv7"}],["path",{d:"M9 3v18",key:"fh3hqa"}],["path",{d:"m14 9 3 3-3 3",key:"8010ee"}]],k1=No("panel-left-open",S1);const w1=[["path",{d:"M18 6 6 18",key:"1bl5f8"}],["path",{d:"m6 6 12 12",key:"d8bk6v"}]],Rc=No("x",w1),T1=L.memo(function({workflow:n,selected:i,onSelect:o}){return v.jsxs("button",{type:"button",className:`tree-select grid w-full min-w-0 cursor-pointer grid-cols-[23px_minmax(0,1fr)] gap-1 rounded-[7px] border-0 bg-transparent p-2 text-left hover:bg-[#f1f4f2] [&_strong]:block [&_strong]:overflow-hidden [&_strong]:text-ellipsis [&_strong]:whitespace-nowrap [&_strong]:text-[11px] [&_strong]:font-semibold [&_small]:mt-[3px] [&_small]:block [&_small]:overflow-hidden [&_small]:text-ellipsis [&_small]:whitespace-nowrap [&_small]:text-[8px] [&_small]:text-secondary ${i?"active bg-[#f1f4f2] shadow-[inset_2px_0_#2563eb]":""}`,onClick:()=>o({kind:"workflow",workflowId:n.workflowId}),children:[v.jsx("span",{className:"workflow-glyph text-base text-acid",children:"◇"}),v.jsxs("span",{children:[v.jsx("strong",{children:n.displayName}),v.jsx("small",{children:n.relativeFile})]})]})});function E1({catalog:a,selection:n,onSelect:i,onCollapse:o,open:u=!1,collapsed:s=!1}){const d=o?v.jsx("button",{type:"button",className:"explorer-collapse-button absolute top-4 right-3.5 grid size-7 cursor-pointer place-items-center rounded-[7px] border border-line bg-white p-0 text-secondary hover:border-secondary hover:bg-[#f7f9f8] hover:text-ink focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-acid max-[700px]:hidden","aria-label":"Collapse Explorer","aria-controls":"operator-explorer","aria-expanded":"true",onClick:o,children:v.jsx(v1,{"aria-hidden":"true",className:"size-4",strokeWidth:1.8})}):null;return a?v.jsxs("aside",{id:"operator-explorer",className:`explorer col-start-1 min-w-0 overflow-auto bg-panel max-[700px]:border-r max-[700px]:border-line max-[700px]:fixed max-[700px]:top-[58px] max-[700px]:bottom-0 max-[700px]:left-0 max-[700px]:z-[31] max-[700px]:w-[min(320px,100vw)] max-[700px]:shadow-[18px_0_45px_rgba(20,31,26,.16)] ${s?"invisible overflow-hidden border-r-0 max-[700px]:visible max-[700px]:overflow-auto max-[700px]:border-r":""} ${u?"max-[700px]:block":"max-[700px]:hidden"}`,"aria-label":"Explorer",children:[v.jsxs("header",{className:"relative px-[18px] pt-[22px] pb-3.5",children:[v.jsx("span",{className:"eyebrow block font-mono text-[9px] tracking-[.16em] text-acid uppercase",children:"Navigator"}),v.jsx("h2",{className:"mt-[5px] text-[17px]",children:"Explorer"}),v.jsxs("span",{className:"catalog-revision absolute right-[18px] bottom-[17px] font-mono text-[9px] text-secondary",children:["catalog r",a.revision]}),d]}),a.diagnostics.length>0&&v.jsxs("details",{className:"diagnostics mx-3 mb-3 rounded-lg border border-[#ead1a2] bg-[#fff8eb] p-[9px] text-[10px] [&>summary]:cursor-pointer [&>summary]:text-amber [&>div]:mt-[9px] [&>div]:border-t [&>div]:border-[#ead1a2] [&>div]:pt-2 [&_strong]:block [&_span]:block [&_span]:overflow-hidden [&_span]:text-ellipsis [&_span]:font-mono [&_span]:text-[8px] [&_span]:text-[#8b7655] [&_p]:mt-1 [&_p]:mb-0 [&_p]:text-[#735b37]",open:!0,children:[v.jsxs("summary",{children:[a.diagnostics.length," reload issue",a.diagnostics.length===1?"":"s"]}),a.diagnostics.map(h=>v.jsxs("div",{children:[v.jsx("strong",{children:h.kind.replaceAll("_"," ")}),v.jsx("span",{children:h.path}),v.jsx("p",{children:h.message})]},`${h.path}-${h.kind}`))]}),v.jsxs("div",{className:"workflow-list mx-2.5 mt-0 border-t border-line px-0 pt-2 pb-[30px]",children:[a.workflows.map(h=>v.jsx(T1,{workflow:h,selected:n?.kind==="workflow"&&n.workflowId===h.workflowId,onSelect:i},h.workflowId)),a.workflows.length===0&&v.jsx("span",{className:"workflow-list-empty block px-2 py-2.5 font-mono text-[9px] text-secondary",children:"No workflows scanned"})]})]}):v.jsxs("aside",{id:"operator-explorer",className:`explorer skeleton col-start-1 min-w-0 overflow-auto bg-panel p-5 max-[700px]:border-r max-[700px]:border-line max-[700px]:fixed max-[700px]:top-[58px] max-[700px]:bottom-0 max-[700px]:left-0 max-[700px]:z-[31] max-[700px]:w-[min(320px,100vw)] max-[700px]:shadow-[18px_0_45px_rgba(20,31,26,.16)] [&>div]:mb-[9px] [&>div]:h-[38px] [&>div]:animate-pulse [&>div]:rounded-[7px] [&>div]:bg-[#edf1ef] ${s?"invisible overflow-hidden border-r-0 max-[700px]:visible max-[700px]:overflow-auto max-[700px]:border-r":""} ${u?"max-[700px]:block":"max-[700px]:hidden"}`,"aria-label":"Explorer",children:[d,v.jsx("div",{}),v.jsx("div",{}),v.jsx("div",{})]})}const _1=L.memo(E1);function mn(a){return typeof a=="object"&&a!==null&&!Array.isArray(a)}function A1(a){return Array.isArray(a)?a.flatMap(n=>mn(n)&&typeof n.name=="string"?[{name:n.name,instructions:typeof n.instructions=="string"?n.instructions:""}]:[]):[]}function N1(a){return Array.isArray(a)?a.flatMap(n=>mn(n)&&typeof n.name=="string"?[{name:n.name,description:typeof n.description=="string"?n.description:""}]:[]):[]}function So(a){return Array.isArray(a)?a.flatMap(n=>!mn(n)||typeof n.name!="string"?[]:[{name:n.name,type:typeof n.type=="string"?n.type:typeof n.annotation=="string"?n.annotation:void 0,description:typeof n.description=="string"?n.description:void 0}]):[]}function dg(a){if(a)try{const n=JSON.parse(a);if(!mn(n))return;const i=mn(n.signature)?n.signature:{};return{instructions:typeof i.instructions=="string"?i.instructions:"",inputs:So(i.inputs),outputs:So(i.outputs),model:n.models,runtime:n.runtime,skills:A1(n.skills),tools:N1(n.tools)}}catch{return}}function hg(a){if(a)try{const n=JSON.parse(a);return mn(n)?{inputs:So(n.inputs),outputs:So(n.outputs)}:void 0}catch{return}}function z1(a){const[n]=a?.split(/\r?\n/,1)??[];return n?.trim()||void 0}const R1=1,O1=1.2,pg=L.memo(({startedAt:a,endedAt:n,runningElapsedSeconds:i,running:o,compact:u})=>{const[s,d]=L.useState(()=>performance.now()),h=L.useRef(void 0),m=o&&n===void 0;m&&(h.current?.startedAt!==a||h.current.elapsedSeconds!==i)&&(h.current={startedAt:a,elapsedSeconds:i,receivedAtMs:performance.now()}),L.useEffect(()=>{if(!m)return;d(performance.now());const g=window.setInterval(()=>d(performance.now()),100);return()=>window.clearInterval(g)},[m,i,a]);const p=n!==void 0?Math.max(0,n-a):m?Math.max(0,(h.current?.elapsedSeconds??i)+(s-(h.current?.receivedAtMs??s))/1e3):0;return v.jsxs("span",{className:`node-duration absolute font-mono text-muted transition-[font-size] duration-150 ease-out motion-reduce:transition-none ${u?"top-3 right-3 text-sm":"top-4 right-4 text-[9px]"}`,children:[p.toFixed(1),"s"]})});pg.displayName="NodeDuration";const mg=L.memo(({data:a,selected:n})=>{const{screenToFlowPosition:i,setCenter:o}=O0(),{zoom:u}=C0(),s=u{const b=g.currentTarget.getBoundingClientRect(),k=i({x:b.left+b.width/2,y:b.top+b.height/2});a.onOpen(),window.requestAnimationFrame(()=>{window.requestAnimationFrame(()=>{o(k.x,k.y,{zoom:O1,duration:200})})})},[a.onOpen,i,o]),h=a.isAgent?"node-agent before:pointer-events-none before:absolute before:inset-y-3 before:left-0 before:w-[3px] before:rounded-r-full before:bg-agent before:content-['']":"",m=a.status==="success"?"text-success":a.status==="failed"?"text-failed":"text-muted",p=a.status==="success"?"status-success":a.status==="failed"?"status-failed":a.status==="running"?"status-running gradient-animate border-[3px]":"blueprint";return v.jsxs("article",{className:`node-card ${s?"node-card--compact min-h-[100px] justify-center gap-0 px-4 py-3":"min-h-[130px] gap-2 p-4"} relative flex w-[360px] cursor-pointer flex-col items-stretch rounded-xl border border-line bg-panel text-left shadow-[0_8px_24px_rgba(25,39,32,.08)] transition-[border-color,box-shadow,transform] duration-150 ease-out hover:-translate-y-px hover:border-acid hover:shadow-[0_10px_28px_rgba(25,39,32,.12)] motion-reduce:transition-none ${n&&a.status!=="running"?"border-acid!":""} ${h} ${p}`,"data-node-kind":a.isAgent?"agent":"standard",children:[v.jsx(oo,{id:"target-left",className:"node-handle pointer-events-none size-px! min-h-0! min-w-0! border-0! bg-transparent! opacity-0",type:"target",position:so.Left,isConnectable:!1}),v.jsx(oo,{id:"target-bottom",className:"node-handle pointer-events-none size-px! min-h-0! min-w-0! border-0! bg-transparent! opacity-0",type:"target",position:so.Bottom,isConnectable:!1}),v.jsx("button",{type:"button",className:"node-card-action absolute inset-0 z-[2] cursor-pointer rounded-[inherit] border-0 bg-transparent p-0 focus-visible:outline-3 focus-visible:outline-offset-3 focus-visible:outline-acid",onClick:d,"aria-label":`Inspect ${a.label}${a.identity?` ${a.identity}`:""}`}),v.jsxs("header",{className:`node-header relative flex flex-col ${s?"min-h-0 items-center justify-center gap-0 pr-0 text-center":"min-h-10 items-start gap-1"}`,children:[v.jsx("span",{className:`node-card-meta node-kicker font-mono text-[8px] tracking-[.12em] uppercase ${a.isAgent?"text-agent":"text-secondary"}`,children:a.isAgent?"agent":a.nodeType}),v.jsxs("strong",{className:`node-title block self-stretch ${s?"text-xl":"pr-[76px] text-sm"} leading-tight text-ink`,children:[a.label,a.status==="success"&&v.jsx(b1,{"aria-hidden":"true",className:`node-status-icon ml-1 inline-block text-success transition-[width,height] duration-200 ease-out motion-reduce:transition-none ${s?"size-6 align-[-0.15em]":"size-3 align-[-0.08em]"}`,strokeWidth:2.5}),a.status==="failed"&&v.jsx(Rc,{"aria-hidden":"true",className:`node-status-icon ml-1 inline-block text-failed transition-[width,height] duration-200 ease-out motion-reduce:transition-none ${s?"size-6 align-[-0.15em]":"size-3 align-[-0.08em]"}`,strokeWidth:2.5})]}),a.instructionLine&&v.jsx("span",{className:"node-card-meta node-instruction-line min-w-0 self-stretch overflow-hidden text-ellipsis line-clamp-2 font-mono text-[9px] leading-[1.35] text-secondary",title:a.instructionLine,children:a.instructionLine}),a.identity&&v.jsx("span",{className:"node-card-meta node-identity font-mono text-[9px] text-secondary",children:a.identity}),a.status&&v.jsx("span",{className:`node-card-meta node-status absolute top-[19px] right-0 font-mono text-[8px] uppercase ${m}`,children:a.status})]}),a.startedAt&&v.jsx(pg,{startedAt:a.startedAt,endedAt:a.endedAt,runningElapsedSeconds:a.runningElapsedSeconds??0,running:a.status==="running",compact:s}),a.declaration&&v.jsxs("div",{className:`node-card-details field-grid grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] overflow-hidden ${s?"min-h-0! max-h-0! gap-0! border-t-transparent! pt-0! opacity-0 pointer-events-none":"min-h-[58px] gap-6 border-t border-line pt-2.5"}`,children:[v.jsxs("section",{className:"node-fields node-inputs min-w-0 overflow-hidden [&>small]:mb-1.5 [&>small]:block [&>small]:font-mono [&>small]:text-[7px] [&>small]:tracking-[.08em] [&>small]:text-muted [&>small]:uppercase","aria-label":"Inputs",children:[v.jsx("small",{children:"Inputs"}),a.declaration.inputs.length?a.declaration.inputs.map(g=>v.jsxs("span",{className:"field node-field mt-[3px] flex min-h-3.5 min-w-0 items-start justify-start gap-1 font-mono text-[7px]/[1.35] text-[#36423c] [&>code]:min-w-0 [&>code]:[overflow-wrap:anywhere] [&>code]:text-[7px] [&>code]:text-muted",children:[v.jsx("span",{className:"node-field-name min-w-0 [overflow-wrap:anywhere]",children:g.name}),g.type&&v.jsx("code",{children:g.type})]},`input-${g.name}`)):v.jsx("span",{className:"node-field-empty font-mono text-[7px] text-muted",children:"None"})]}),v.jsxs("section",{className:"node-fields node-outputs min-w-0 overflow-hidden text-right [&>small]:mb-1.5 [&>small]:block [&>small]:font-mono [&>small]:text-[7px] [&>small]:tracking-[.08em] [&>small]:text-muted [&>small]:uppercase","aria-label":"Outputs",children:[v.jsx("small",{children:"Outputs"}),a.declaration.outputs.length?a.declaration.outputs.map(g=>v.jsxs("span",{className:"field node-field mt-[3px] flex min-h-3.5 min-w-0 items-start justify-end gap-1 font-mono text-[7px]/[1.35] text-[#36423c] [&>code]:min-w-0 [&>code]:[overflow-wrap:anywhere] [&>code]:text-[7px] [&>code]:text-muted",children:[v.jsx("span",{className:"node-field-name min-w-0 [overflow-wrap:anywhere]",children:g.name}),g.type&&v.jsx("code",{children:g.type})]},`output-${g.name}`)):v.jsx("span",{className:"node-field-empty font-mono text-[7px] text-muted",children:"None"})]})]}),v.jsx(oo,{id:"source-right",className:"node-handle pointer-events-none size-px! min-h-0! min-w-0! border-0! bg-transparent! opacity-0",type:"source",position:so.Right,isConnectable:!1}),v.jsx(oo,{id:"source-bottom",className:"node-handle pointer-events-none size-px! min-h-0! min-w-0! border-0! bg-transparent! opacity-0",type:"source",position:so.Bottom,isConnectable:!1})]})});mg.displayName="WorkflowNodeCard";const C1=56,D1=32,gg=L.memo(({data:a,markerEnd:n,sourceX:i,sourceY:o,style:u,targetX:s,targetY:d})=>{const h=D0(g=>Math.max(...Array.from(g.nodeLookup.values(),b=>b.internals.positionAbsolute.y+(b.measured.height??0))));if(a===void 0)throw new Error("Skip edge is missing its routing lane");const m=h+C1+a.lane*D1,p=`M ${i},${o} L ${i},${m} L ${s},${m} L ${s},${d}`;return v.jsx(M0,{path:p,markerEnd:n,style:u})});gg.displayName="SkipEdge";const M1={workflow:mg},j1={skip:gg},L1={padding:.24};function B1(a,n){const i=a.startsWith(`${n}_`)?a.slice(n.length+1):"";return i&&/^\d+$/.test(i)?`#${i}`:a}function U1(a){const n=Object.fromEntries(a.nodeIds.map(p=>[p,0]));for(const p of Object.values(a.graph))for(const g of p.children)n[g]=(n[g]??0)+1;const i={},o=a.nodeIds.filter(p=>n[p]===0);for(const p of o)i[p]=0;for(let p=0;pg.map((b,k)=>[b,{x:Number(p)*500,y:k*220-(g.length-1)*110}]))),d=new Set,h=[];let m=0;for(const[p,g]of Object.entries(a.graph))for(const b of g.children){const k=`${p}->${b}`;if(d.has(k))continue;d.add(k);const S=i[b]!==(i[p]??0)+1;h.push({id:k,source:p,target:b,sourceHandle:S?"source-bottom":"source-right",targetHandle:S?"target-bottom":"target-left",markerEnd:{type:I0.ArrowClosed},type:S?"skip":"step",data:S?{lane:m++}:void 0,className:"dag-edge"})}return{edges:h,positions:s}}function I1({workflow:a,runTopology:n,runNodes:i=[],topLeftPanel:o,bottomRightPanel:u,selectedNodeId:s,onClearNode:d,onOpenNode:h}){const m=a!==void 0&&n===void 0,p=L.useMemo(()=>{if(n)return n;if(a)return{nodeIds:a.nodeIds,graph:a.graph,nodeTypes:a.nodeTypes,displayNames:a.displayNames,agentInstructionLines:{}}},[n,a]),g=p?.nodeIds,b=p?.graph,k=L.useMemo(()=>g&&b?U1({nodeIds:g,graph:b}):{edges:[],positions:{}},[b,g]),S=L.useMemo(()=>Object.fromEntries((g??[]).map(X=>[X,()=>h(X)])),[h,g]),j=L.useMemo(()=>new Set(n?Object.keys(n.agentFieldSchemasJson):a?.agentNodeIds??[]),[n,a]),I=L.useMemo(()=>{if(!p)return[];const X=Object.fromEntries(i.map(F=>[F.nodeId,F])),D=Object.fromEntries(p.nodeIds.map(F=>[F,p.displayNames[F]||X[F]?.name||F])),G=Object.values(D).reduce((F,te)=>({...F,[te]:(F[te]??0)+1}),{});return p.nodeIds.map(F=>{const te=X[F],q=n?void 0:dg(a?.agentMetadataJson[F]),re=n?hg(n.agentFieldSchemasJson[F]):q,ue=n?n.agentInstructionLines[F]||void 0:z1(q?.instructions);return{id:F,selected:F===s,type:"workflow",position:k.positions[F],data:{label:D[F],identity:G[D[F]]>1?B1(F,D[F]):void 0,nodeType:p.nodeTypes[F]||te?.nodeType||"step",isAgent:j.has(F),status:te?.status,error:te?.error,startedAt:te?.startedAt||void 0,endedAt:te?.endedAt||void 0,runningElapsedSeconds:te?.runningElapsedSeconds??0,declaration:re,instructionLine:ue,onOpen:S[F]}}})},[j,k.positions,S,i,n,s,p,a]);return v.jsxs(j0,{className:"[&_.react-flow__edge-path]:stroke-[#87938d] [&_.react-flow__edge-path]:[stroke-width:1.4] [&_.react-flow__arrowhead_polyline]:fill-[#87938d] [&_.react-flow__arrowhead_polyline]:stroke-[#87938d]",nodes:I,edges:k.edges,nodeTypes:M1,edgeTypes:j1,fitView:!0,fitViewOptions:L1,minZoom:.25,maxZoom:1.8,nodesDraggable:!1,nodesConnectable:!1,elementsSelectable:!0,onPaneClick:d,proOptions:{hideAttribution:!0},children:[o&&v.jsx(lm,{position:"top-left",className:"dag-panel dag-runs-panel nodrag nopan nowheel m-3.5 flex items-start gap-2",children:o}),u&&v.jsx(lm,{position:"bottom-right",className:"dag-panel dag-actions-panel nodrag nopan m-3.5 rounded-[9px] border border-line bg-[rgba(255,255,255,.96)] p-[7px] shadow-[0_6px_20px_rgba(20,31,26,.1)]",children:u}),v.jsx(L0,{color:m?"#dfe4e1":"rgba(255,255,255,.06)",variant:B0.Dots,gap:m?18:24,size:m?2.5:1}),v.jsx(U0,{className:"overflow-hidden rounded-lg border! border-line! bg-white! shadow-[0_4px_14px_rgba(20,31,26,.08)]! [&_.react-flow__controls-button]:border-b-line! [&_.react-flow__controls-button]:bg-white! [&_.react-flow__controls-button]:fill-secondary! [&_.react-flow__controls-button:hover]:bg-[#f1f4f2]!",showInteractive:!1})]})}function q1(a,n){return a===n?!0:(a?.length??0)!==(n?.length??0)?!1:(a??[]).every((i,o)=>{const u=n?.[o];return u!==void 0&&i.nodeId===u.nodeId&&i.name===u.name&&i.nodeType===u.nodeType&&i.status===u.status&&i.error===u.error&&i.startedAt===u.startedAt&&i.endedAt===u.endedAt})}const dm=L.memo(I1,(a,n)=>a.workflow===n.workflow&&a.runTopology===n.runTopology&&a.topLeftPanel===n.topLeftPanel&&a.bottomRightPanel===n.bottomRightPanel&&a.selectedNodeId===n.selectedNodeId&&a.onClearNode===n.onClearNode&&a.onOpenNode===n.onOpenNode&&q1(a.runNodes,n.runNodes)),ko=100,uo=500,ji=8*1024*1024,wo=96;function Oc(a,n){return a.length!==n.length?a.length-n.length:an?1:0}function Gc(a,n,i,o=[]){const u=[...a.values()].sort((m,p)=>Oc(n(m),n(p)));if(u.length<=uo)return u;const s=new Set(o),d=[],h=[];for(const m of u)(s.has(n(m))?d:h).push(m);return[...i==="newer"?h.slice(-(uo-d.length)):h.slice(0,uo-d.length),...d].sort((m,p)=>Oc(n(m),n(p))).slice(-uo)}function yg(a,n,i,o,u=[]){const s=new Map;for(const d of a.records)s.set(i(d),d);for(const d of n.records)s.set(i(d),d);return{...n,records:Gc(s,i,o,u)}}function Ia(a,n){const i=Number(n);let o=0;try{const u=typeof a=="string"?a:JSON.stringify(a)??"";o=new TextEncoder().encode(u).byteLength}catch{o=ji+1}return Math.max(Number.isFinite(i)&&i>0?i:0,o)}function H1(a,n){const i={};return(a[a.length-1]===""?[...a,""]:a).join((i.padRight?" ":"")+","+(i.padLeft===!1?"":" ")).trim()}const V1=/^[$_\p{ID_Start}][$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,G1=/^[$_\p{ID_Start}][-$_\u{200C}\u{200D}\p{ID_Continue}]*$/u,Y1={};function hm(a,n){return(Y1.jsx?G1:V1).test(a)}const F1=/[ \t\n\f\r]/g;function X1(a){return typeof a=="object"?a.type==="text"?pm(a.value):!1:pm(a)}function pm(a){return a.replace(F1,"")===""}class Ya{constructor(n,i,o){this.normal=i,this.property=n,o&&(this.space=o)}}Ya.prototype.normal={};Ya.prototype.property={};Ya.prototype.space=void 0;function bg(a,n){const i={},o={};for(const u of a)Object.assign(i,u.property),Object.assign(o,u.normal);return new Ya(i,o,n)}function Cc(a){return a.toLowerCase()}class Ft{constructor(n,i){this.attribute=i,this.property=n}}Ft.prototype.attribute="";Ft.prototype.booleanish=!1;Ft.prototype.boolean=!1;Ft.prototype.commaOrSpaceSeparated=!1;Ft.prototype.commaSeparated=!1;Ft.prototype.defined=!1;Ft.prototype.mustUseProperty=!1;Ft.prototype.number=!1;Ft.prototype.overloadedBoolean=!1;Ft.prototype.property="";Ft.prototype.spaceSeparated=!1;Ft.prototype.space=void 0;let Q1=0;const Te=Vl(),bt=Vl(),Dc=Vl(),P=Vl(),tt=Vl(),Hl=Vl(),Pt=Vl();function Vl(){return 2**++Q1}const Mc=Object.freeze(Object.defineProperty({__proto__:null,boolean:Te,booleanish:bt,commaOrSpaceSeparated:Pt,commaSeparated:Hl,number:P,overloadedBoolean:Dc,spaceSeparated:tt},Symbol.toStringTag,{value:"Module"})),fc=Object.keys(Mc);class Yc extends Ft{constructor(n,i,o,u){let s=-1;if(super(n,i),mm(this,"space",u),typeof o=="number")for(;++s4&&i.slice(0,4)==="data"&&W1.test(n)){if(n.charAt(4)==="-"){const s=n.slice(5).replace(gm,tv);o="data"+s.charAt(0).toUpperCase()+s.slice(1)}else{const s=n.slice(4);if(!gm.test(s)){let d=s.replace(J1,ev);d.charAt(0)!=="-"&&(d="-"+d),n="data"+d}}u=Yc}return new u(o,n)}function ev(a){return"-"+a.toLowerCase()}function tv(a){return a.charAt(1).toUpperCase()}const nv=bg([xg,K1,kg,wg,Tg],"html"),Fc=bg([xg,$1,kg,wg,Tg],"svg");function lv(a){return a.join(" ").trim()}var Ai={},dc,ym;function iv(){if(ym)return dc;ym=1;var a=/\/\*[^*]*\*+([^/*][^*]*\*+)*\//g,n=/\n/g,i=/^\s*/,o=/^(\*?[-#/*\\\w]+(\[[0-9a-z_-]+\])?)\s*/,u=/^:\s*/,s=/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^)]*?\)|[^};])+)/,d=/^[;\s]*/,h=/^\s+|\s+$/g,m=` +`,p="/",g="*",b="",k="comment",S="declaration";function j(X,D){if(typeof X!="string")throw new TypeError("First argument must be a string");if(!X)return[];D=D||{};var G=1,B=1;function F(ne){var $=ne.match(n);$&&(G+=$.length);var R=ne.lastIndexOf(m);B=~R?ne.length-R:B+ne.length}function te(){var ne={line:G,column:B};return function($){return $.position=new q(ne),de(),$}}function q(ne){this.start=ne,this.end={line:G,column:B},this.source=D.source}q.prototype.content=X;function re(ne){var $=new Error(D.source+":"+G+":"+B+": "+ne);if($.reason=ne,$.filename=D.source,$.line=G,$.column=B,$.source=X,!D.silent)throw $}function ue(ne){var $=ne.exec(X);if($){var R=$[0];return F(R),X=X.slice(R.length),$}}function de(){ue(i)}function pe(ne){var $;for(ne=ne||[];$=le();)$!==!1&&ne.push($);return ne}function le(){var ne=te();if(!(p!=X.charAt(0)||g!=X.charAt(1))){for(var $=2;b!=X.charAt($)&&(g!=X.charAt($)||p!=X.charAt($+1));)++$;if($+=2,b===X.charAt($-1))return re("End of comment missing");var R=X.slice(2,$-2);return B+=2,F(R),X=X.slice($),B+=2,ne({type:k,comment:R})}}function Z(){var ne=te(),$=ue(o);if($){if(le(),!ue(u))return re("property missing ':'");var R=ue(s),K=ne({type:S,property:I($[0].replace(a,b)),value:R?I(R[0].replace(a,b)):b});return ue(d),K}}function me(){var ne=[];pe(ne);for(var $;$=Z();)$!==!1&&(ne.push($),pe(ne));return ne}return de(),me()}function I(X){return X?X.replace(h,b):b}return dc=j,dc}var bm;function av(){if(bm)return Ai;bm=1;var a=Ai&&Ai.__importDefault||function(o){return o&&o.__esModule?o:{default:o}};Object.defineProperty(Ai,"__esModule",{value:!0}),Ai.default=i;const n=a(iv());function i(o,u){let s=null;if(!o||typeof o!="string")return s;const d=(0,n.default)(o),h=typeof u=="function";return d.forEach(m=>{if(m.type!=="declaration")return;const{property:p,value:g}=m;h?u(p,g,m):g&&(s=s||{},s[p]=g)}),s}return Ai}var Da={},xm;function rv(){if(xm)return Da;xm=1,Object.defineProperty(Da,"__esModule",{value:!0}),Da.camelCase=void 0;var a=/^--[a-zA-Z0-9_-]+$/,n=/-([a-z])/g,i=/^[^-]+$/,o=/^-(webkit|moz|ms|o|khtml)-/,u=/^-(ms)-/,s=function(p){return!p||i.test(p)||a.test(p)},d=function(p,g){return g.toUpperCase()},h=function(p,g){return"".concat(g,"-")},m=function(p,g){return g===void 0&&(g={}),s(p)?p:(p=p.toLowerCase(),g.reactCompat?p=p.replace(u,h):p=p.replace(o,h),p.replace(n,d))};return Da.camelCase=m,Da}var Ma,vm;function ov(){if(vm)return Ma;vm=1;var a=Ma&&Ma.__importDefault||function(u){return u&&u.__esModule?u:{default:u}},n=a(av()),i=rv();function o(u,s){var d={};return!u||typeof u!="string"||(0,n.default)(u,function(h,m){h&&m&&(d[(0,i.camelCase)(h,s)]=m)}),d}return o.default=o,Ma=o,Ma}var sv=ov();const uv=cg(sv),Eg=_g("end"),Xc=_g("start");function _g(a){return n;function n(i){const o=i&&i.position&&i.position[a]||{};if(typeof o.line=="number"&&o.line>0&&typeof o.column=="number"&&o.column>0)return{line:o.line,column:o.column,offset:typeof o.offset=="number"&&o.offset>-1?o.offset:void 0}}}function cv(a){const n=Xc(a),i=Eg(a);if(n&&i)return{start:n,end:i}}function qa(a){return!a||typeof a!="object"?"":"position"in a||"type"in a?Sm(a.position):"start"in a||"end"in a?Sm(a):"line"in a||"column"in a?jc(a):""}function jc(a){return km(a&&a.line)+":"+km(a&&a.column)}function Sm(a){return jc(a&&a.start)+"-"+jc(a&&a.end)}function km(a){return a&&typeof a=="number"?a:1}class Ct extends Error{constructor(n,i,o){super(),typeof i=="string"&&(o=i,i=void 0);let u="",s={},d=!1;if(i&&("line"in i&&"column"in i?s={place:i}:"start"in i&&"end"in i?s={place:i}:"type"in i?s={ancestors:[i],place:i.position}:s={...i}),typeof n=="string"?u=n:!s.cause&&n&&(d=!0,u=n.message,s.cause=n),!s.ruleId&&!s.source&&typeof o=="string"){const m=o.indexOf(":");m===-1?s.ruleId=o:(s.source=o.slice(0,m),s.ruleId=o.slice(m+1))}if(!s.place&&s.ancestors&&s.ancestors){const m=s.ancestors[s.ancestors.length-1];m&&(s.place=m.position)}const h=s.place&&"start"in s.place?s.place.start:s.place;this.ancestors=s.ancestors||void 0,this.cause=s.cause||void 0,this.column=h?h.column:void 0,this.fatal=void 0,this.file="",this.message=u,this.line=h?h.line:void 0,this.name=qa(s.place)||"1:1",this.place=s.place||void 0,this.reason=this.message,this.ruleId=s.ruleId||void 0,this.source=s.source||void 0,this.stack=d&&s.cause&&typeof s.cause.stack=="string"?s.cause.stack:"",this.actual=void 0,this.expected=void 0,this.note=void 0,this.url=void 0}}Ct.prototype.file="";Ct.prototype.name="";Ct.prototype.reason="";Ct.prototype.message="";Ct.prototype.stack="";Ct.prototype.column=void 0;Ct.prototype.line=void 0;Ct.prototype.ancestors=void 0;Ct.prototype.cause=void 0;Ct.prototype.fatal=void 0;Ct.prototype.place=void 0;Ct.prototype.ruleId=void 0;Ct.prototype.source=void 0;const Qc={}.hasOwnProperty,fv=new Map,dv=/[A-Z]/g,hv=new Set(["table","tbody","thead","tfoot","tr"]),pv=new Set(["td","th"]),Ag="https://github.com/syntax-tree/hast-util-to-jsx-runtime";function mv(a,n){if(!n||n.Fragment===void 0)throw new TypeError("Expected `Fragment` in options");const i=n.filePath||void 0;let o;if(n.development){if(typeof n.jsxDEV!="function")throw new TypeError("Expected `jsxDEV` in options when `development: true`");o=wv(i,n.jsxDEV)}else{if(typeof n.jsx!="function")throw new TypeError("Expected `jsx` in production options");if(typeof n.jsxs!="function")throw new TypeError("Expected `jsxs` in production options");o=kv(i,n.jsx,n.jsxs)}const u={Fragment:n.Fragment,ancestors:[],components:n.components||{},create:o,elementAttributeNameCase:n.elementAttributeNameCase||"react",evaluater:n.createEvaluater?n.createEvaluater():void 0,filePath:i,ignoreInvalidStyle:n.ignoreInvalidStyle||!1,passKeys:n.passKeys!==!1,passNode:n.passNode||!1,schema:n.space==="svg"?Fc:nv,stylePropertyNameCase:n.stylePropertyNameCase||"dom",tableCellAlignToStyle:n.tableCellAlignToStyle!==!1},s=Ng(u,a,void 0);return s&&typeof s!="string"?s:u.create(a,u.Fragment,{children:s||void 0},void 0)}function Ng(a,n,i){if(n.type==="element")return gv(a,n,i);if(n.type==="mdxFlowExpression"||n.type==="mdxTextExpression")return yv(a,n);if(n.type==="mdxJsxFlowElement"||n.type==="mdxJsxTextElement")return xv(a,n,i);if(n.type==="mdxjsEsm")return bv(a,n);if(n.type==="root")return vv(a,n,i);if(n.type==="text")return Sv(a,n)}function gv(a,n,i){const o=a.schema;let u=o;n.tagName.toLowerCase()==="svg"&&o.space==="html"&&(u=Fc,a.schema=u),a.ancestors.push(n);const s=Rg(a,n.tagName,!1),d=Tv(a,n);let h=$c(a,n);return hv.has(n.tagName)&&(h=h.filter(function(m){return typeof m=="string"?!X1(m):!0})),zg(a,d,s,n),Kc(d,h),a.ancestors.pop(),a.schema=o,a.create(n,s,d,i)}function yv(a,n){if(n.data&&n.data.estree&&a.evaluater){const o=n.data.estree.body[0];return o.type,a.evaluater.evaluateExpression(o.expression)}Ga(a,n.position)}function bv(a,n){if(n.data&&n.data.estree&&a.evaluater)return a.evaluater.evaluateProgram(n.data.estree);Ga(a,n.position)}function xv(a,n,i){const o=a.schema;let u=o;n.name==="svg"&&o.space==="html"&&(u=Fc,a.schema=u),a.ancestors.push(n);const s=n.name===null?a.Fragment:Rg(a,n.name,!0),d=Ev(a,n),h=$c(a,n);return zg(a,d,s,n),Kc(d,h),a.ancestors.pop(),a.schema=o,a.create(n,s,d,i)}function vv(a,n,i){const o={};return Kc(o,$c(a,n)),a.create(n,a.Fragment,o,i)}function Sv(a,n){return n.value}function zg(a,n,i,o){typeof i!="string"&&i!==a.Fragment&&a.passNode&&(n.node=o)}function Kc(a,n){if(n.length>0){const i=n.length>1?n:n[0];i&&(a.children=i)}}function kv(a,n,i){return o;function o(u,s,d,h){const p=Array.isArray(d.children)?i:n;return h?p(s,d,h):p(s,d)}}function wv(a,n){return i;function i(o,u,s,d){const h=Array.isArray(s.children),m=Xc(o);return n(u,s,d,h,{columnNumber:m?m.column-1:void 0,fileName:a,lineNumber:m?m.line:void 0},void 0)}}function Tv(a,n){const i={};let o,u;for(u in n.properties)if(u!=="children"&&Qc.call(n.properties,u)){const s=_v(a,u,n.properties[u]);if(s){const[d,h]=s;a.tableCellAlignToStyle&&d==="align"&&typeof h=="string"&&pv.has(n.tagName)?o=h:i[d]=h}}if(o){const s=i.style||(i.style={});s[a.stylePropertyNameCase==="css"?"text-align":"textAlign"]=o}return i}function Ev(a,n){const i={};for(const o of n.attributes)if(o.type==="mdxJsxExpressionAttribute")if(o.data&&o.data.estree&&a.evaluater){const s=o.data.estree.body[0];s.type;const d=s.expression;d.type;const h=d.properties[0];h.type,Object.assign(i,a.evaluater.evaluateExpression(h.argument))}else Ga(a,n.position);else{const u=o.name;let s;if(o.value&&typeof o.value=="object")if(o.value.data&&o.value.data.estree&&a.evaluater){const h=o.value.data.estree.body[0];h.type,s=a.evaluater.evaluateExpression(h.expression)}else Ga(a,n.position);else s=o.value===null?!0:o.value;i[u]=s}return i}function $c(a,n){const i=[];let o=-1;const u=a.passKeys?new Map:fv;for(;++ou?0:u+n:n=n>u?u:n,i=i>0?i:0,o.length<1e4)d=Array.from(o),d.unshift(n,i),a.splice(...d);else for(i&&a.splice(n,i);s0?(An(a,a.length,0,n),a):n}const Em={}.hasOwnProperty;function Mv(a){const n={};let i=-1;for(;++i13&&i<32||i>126&&i<160||i>55295&&i<57344||i>64975&&i<65008||(i&65535)===65535||(i&65535)===65534||i>1114111?"�":String.fromCodePoint(i)}function Li(a){return a.replace(/[\t\n\r ]+/g," ").replace(/^ | $/g,"").toLowerCase().toUpperCase()}const _n=xl(/[A-Za-z]/),en=xl(/[\dA-Za-z]/),Bv=xl(/[#-'*+\--9=?A-Z^-~]/);function Lc(a){return a!==null&&(a<32||a===127)}const Bc=xl(/\d/),Uv=xl(/[\dA-Fa-f]/),Iv=xl(/[!-/:-@[-`{-~]/);function we(a){return a!==null&&a<-2}function Yt(a){return a!==null&&(a<0||a===32)}function Ge(a){return a===-2||a===-1||a===32}const qv=xl(new RegExp("\\p{P}|\\p{S}","u")),Hv=xl(/\s/);function xl(a){return n;function n(i){return i!==null&&i>-1&&a.test(String.fromCharCode(i))}}function Ii(a){const n=[];let i=-1,o=0,u=0;for(;++i55295&&s<57344){const h=a.charCodeAt(i+1);s<56320&&h>56319&&h<57344?(d=String.fromCharCode(s,h),u=1):d="�"}else d=String.fromCharCode(s);d&&(n.push(a.slice(o,i),encodeURIComponent(d)),o=i+u+1,d=""),u&&(i+=u,u=0)}return n.join("")+a.slice(o)}function lt(a,n,i,o){const u=o?o-1:Number.POSITIVE_INFINITY;let s=0;return d;function d(m){return Ge(m)?(a.enter(i),h(m)):n(m)}function h(m){return Ge(m)&&s++d))return;const re=n.events.length;let ue=re,de,pe;for(;ue--;)if(n.events[ue][0]==="exit"&&n.events[ue][1].type==="chunkFlow"){if(de){pe=n.events[ue][1].end;break}de=!0}for(D(o),q=re;qB;){const te=i[F];n.containerState=te[1],te[0].exit.call(n,a)}i.length=B}function G(){u.write([null]),s=void 0,u=void 0,n.containerState._closeFlow=void 0}}function Xv(a,n,i){return lt(a,a.attempt(this.parser.constructs.document,n,i),"linePrefix",this.parser.constructs.disable.null.includes("codeIndented")?void 0:4)}function Am(a){if(a===null||Yt(a)||Hv(a))return 1;if(qv(a))return 2}function Jc(a,n,i){const o=[];let u=-1;for(;++u1&&a[i][1].end.offset-a[i][1].start.offset>1?2:1;const b={...a[o][1].end},k={...a[i][1].start};Nm(b,-m),Nm(k,m),d={type:m>1?"strongSequence":"emphasisSequence",start:b,end:{...a[o][1].end}},h={type:m>1?"strongSequence":"emphasisSequence",start:{...a[i][1].start},end:k},s={type:m>1?"strongText":"emphasisText",start:{...a[o][1].end},end:{...a[i][1].start}},u={type:m>1?"strong":"emphasis",start:{...d.start},end:{...h.end}},a[o][1].end={...d.start},a[i][1].start={...h.end},p=[],a[o][1].end.offset-a[o][1].start.offset&&(p=pn(p,[["enter",a[o][1],n],["exit",a[o][1],n]])),p=pn(p,[["enter",u,n],["enter",d,n],["exit",d,n],["enter",s,n]]),p=pn(p,Jc(n.parser.constructs.insideSpan.null,a.slice(o+1,i),n)),p=pn(p,[["exit",s,n],["enter",h,n],["exit",h,n],["exit",u,n]]),a[i][1].end.offset-a[i][1].start.offset?(g=2,p=pn(p,[["enter",a[i][1],n],["exit",a[i][1],n]])):g=0,An(a,o-1,i-o+3,p),i=o+p.length-g-2;break}}for(i=-1;++i0&&Ge(q)?lt(a,G,"linePrefix",s+1)(q):G(q)}function G(q){return q===null||we(q)?a.check(zm,I,F)(q):(a.enter("codeFlowValue"),B(q))}function B(q){return q===null||we(q)?(a.exit("codeFlowValue"),G(q)):(a.consume(q),B)}function F(q){return a.exit("codeFenced"),n(q)}function te(q,re,ue){let de=0;return pe;function pe($){return q.enter("lineEnding"),q.consume($),q.exit("lineEnding"),le}function le($){return q.enter("codeFencedFence"),Ge($)?lt(q,Z,"linePrefix",o.parser.constructs.disable.null.includes("codeIndented")?void 0:4)($):Z($)}function Z($){return $===h?(q.enter("codeFencedFenceSequence"),me($)):ue($)}function me($){return $===h?(de++,q.consume($),me):de>=d?(q.exit("codeFencedFenceSequence"),Ge($)?lt(q,ne,"whitespace")($):ne($)):ue($)}function ne($){return $===null||we($)?(q.exit("codeFencedFence"),re($)):ue($)}}}function iS(a,n,i){const o=this;return u;function u(d){return d===null?i(d):(a.enter("lineEnding"),a.consume(d),a.exit("lineEnding"),s)}function s(d){return o.parser.lazy[o.now().line]?i(d):n(d)}}const pc={name:"codeIndented",tokenize:rS},aS={partial:!0,tokenize:oS};function rS(a,n,i){const o=this;return u;function u(p){return a.enter("codeIndented"),lt(a,s,"linePrefix",5)(p)}function s(p){const g=o.events[o.events.length-1];return g&&g[1].type==="linePrefix"&&g[2].sliceSerialize(g[1],!0).length>=4?d(p):i(p)}function d(p){return p===null?m(p):we(p)?a.attempt(aS,d,m)(p):(a.enter("codeFlowValue"),h(p))}function h(p){return p===null||we(p)?(a.exit("codeFlowValue"),d(p)):(a.consume(p),h)}function m(p){return a.exit("codeIndented"),n(p)}}function oS(a,n,i){const o=this;return u;function u(d){return o.parser.lazy[o.now().line]?i(d):we(d)?(a.enter("lineEnding"),a.consume(d),a.exit("lineEnding"),u):lt(a,s,"linePrefix",5)(d)}function s(d){const h=o.events[o.events.length-1];return h&&h[1].type==="linePrefix"&&h[2].sliceSerialize(h[1],!0).length>=4?n(d):we(d)?u(d):i(d)}}const sS={name:"codeText",previous:cS,resolve:uS,tokenize:fS};function uS(a){let n=a.length-4,i=3,o,u;if((a[i][1].type==="lineEnding"||a[i][1].type==="space")&&(a[n][1].type==="lineEnding"||a[n][1].type==="space")){for(o=i;++o=this.left.length+this.right.length)throw new RangeError("Cannot access index `"+n+"` in a splice buffer of size `"+(this.left.length+this.right.length)+"`");return nthis.left.length?this.right.slice(this.right.length-o+this.left.length,this.right.length-n+this.left.length).reverse():this.left.slice(n).concat(this.right.slice(this.right.length-o+this.left.length).reverse())}splice(n,i,o){const u=i||0;this.setCursor(Math.trunc(n));const s=this.right.splice(this.right.length-u,Number.POSITIVE_INFINITY);return o&&ja(this.left,o),s.reverse()}pop(){return this.setCursor(Number.POSITIVE_INFINITY),this.left.pop()}push(n){this.setCursor(Number.POSITIVE_INFINITY),this.left.push(n)}pushMany(n){this.setCursor(Number.POSITIVE_INFINITY),ja(this.left,n)}unshift(n){this.setCursor(0),this.right.push(n)}unshiftMany(n){this.setCursor(0),ja(this.right,n.reverse())}setCursor(n){if(!(n===this.left.length||n>this.left.length&&this.right.length===0||n<0&&this.left.length===0))if(n=4?n(d):a.interrupt(o.parser.constructs.flow,i,n)(d)}}function Bg(a,n,i,o,u,s,d,h,m){const p=m||Number.POSITIVE_INFINITY;let g=0;return b;function b(D){return D===60?(a.enter(o),a.enter(u),a.enter(s),a.consume(D),a.exit(s),k):D===null||D===32||D===41||Lc(D)?i(D):(a.enter(o),a.enter(d),a.enter(h),a.enter("chunkString",{contentType:"string"}),I(D))}function k(D){return D===62?(a.enter(s),a.consume(D),a.exit(s),a.exit(u),a.exit(o),n):(a.enter(h),a.enter("chunkString",{contentType:"string"}),S(D))}function S(D){return D===62?(a.exit("chunkString"),a.exit(h),k(D)):D===null||D===60||we(D)?i(D):(a.consume(D),D===92?j:S)}function j(D){return D===60||D===62||D===92?(a.consume(D),S):S(D)}function I(D){return!g&&(D===null||D===41||Yt(D))?(a.exit("chunkString"),a.exit(h),a.exit(d),a.exit(o),n(D)):g999||S===null||S===91||S===93&&!m||S===94&&!h&&"_hiddenFootnoteSupport"in d.parser.constructs?i(S):S===93?(a.exit(s),a.enter(u),a.consume(S),a.exit(u),a.exit(o),n):we(S)?(a.enter("lineEnding"),a.consume(S),a.exit("lineEnding"),g):(a.enter("chunkString",{contentType:"string"}),b(S))}function b(S){return S===null||S===91||S===93||we(S)||h++>999?(a.exit("chunkString"),g(S)):(a.consume(S),m||(m=!Ge(S)),S===92?k:b)}function k(S){return S===91||S===92||S===93?(a.consume(S),h++,b):b(S)}}function Ig(a,n,i,o,u,s){let d;return h;function h(k){return k===34||k===39||k===40?(a.enter(o),a.enter(u),a.consume(k),a.exit(u),d=k===40?41:k,m):i(k)}function m(k){return k===d?(a.enter(u),a.consume(k),a.exit(u),a.exit(o),n):(a.enter(s),p(k))}function p(k){return k===d?(a.exit(s),m(d)):k===null?i(k):we(k)?(a.enter("lineEnding"),a.consume(k),a.exit("lineEnding"),lt(a,p,"linePrefix")):(a.enter("chunkString",{contentType:"string"}),g(k))}function g(k){return k===d||k===null||we(k)?(a.exit("chunkString"),p(k)):(a.consume(k),k===92?b:g)}function b(k){return k===d||k===92?(a.consume(k),g):g(k)}}function Ha(a,n){let i;return o;function o(u){return we(u)?(a.enter("lineEnding"),a.consume(u),a.exit("lineEnding"),i=!0,o):Ge(u)?lt(a,o,i?"linePrefix":"lineSuffix")(u):n(u)}}const xS={name:"definition",tokenize:SS},vS={partial:!0,tokenize:kS};function SS(a,n,i){const o=this;let u;return s;function s(S){return a.enter("definition"),d(S)}function d(S){return Ug.call(o,a,h,i,"definitionLabel","definitionLabelMarker","definitionLabelString")(S)}function h(S){return u=Li(o.sliceSerialize(o.events[o.events.length-1][1]).slice(1,-1)),S===58?(a.enter("definitionMarker"),a.consume(S),a.exit("definitionMarker"),m):i(S)}function m(S){return Yt(S)?Ha(a,p)(S):p(S)}function p(S){return Bg(a,g,i,"definitionDestination","definitionDestinationLiteral","definitionDestinationLiteralMarker","definitionDestinationRaw","definitionDestinationString")(S)}function g(S){return a.attempt(vS,b,b)(S)}function b(S){return Ge(S)?lt(a,k,"whitespace")(S):k(S)}function k(S){return S===null||we(S)?(a.exit("definition"),o.parser.defined.push(u),n(S)):i(S)}}function kS(a,n,i){return o;function o(h){return Yt(h)?Ha(a,u)(h):i(h)}function u(h){return Ig(a,s,i,"definitionTitle","definitionTitleMarker","definitionTitleString")(h)}function s(h){return Ge(h)?lt(a,d,"whitespace")(h):d(h)}function d(h){return h===null||we(h)?n(h):i(h)}}const wS={name:"hardBreakEscape",tokenize:TS};function TS(a,n,i){return o;function o(s){return a.enter("hardBreakEscape"),a.consume(s),u}function u(s){return we(s)?(a.exit("hardBreakEscape"),n(s)):i(s)}}const ES={name:"headingAtx",resolve:_S,tokenize:AS};function _S(a,n){let i=a.length-2,o=3,u,s;return a[o][1].type==="whitespace"&&(o+=2),i-2>o&&a[i][1].type==="whitespace"&&(i-=2),a[i][1].type==="atxHeadingSequence"&&(o===i-1||i-4>o&&a[i-2][1].type==="whitespace")&&(i-=o+1===i?2:4),i>o&&(u={type:"atxHeadingText",start:a[o][1].start,end:a[i][1].end},s={type:"chunkText",start:a[o][1].start,end:a[i][1].end,contentType:"text"},An(a,o,i-o+1,[["enter",u,n],["enter",s,n],["exit",s,n],["exit",u,n]])),a}function AS(a,n,i){let o=0;return u;function u(g){return a.enter("atxHeading"),s(g)}function s(g){return a.enter("atxHeadingSequence"),d(g)}function d(g){return g===35&&o++<6?(a.consume(g),d):g===null||Yt(g)?(a.exit("atxHeadingSequence"),h(g)):i(g)}function h(g){return g===35?(a.enter("atxHeadingSequence"),m(g)):g===null||we(g)?(a.exit("atxHeading"),n(g)):Ge(g)?lt(a,h,"whitespace")(g):(a.enter("atxHeadingText"),p(g))}function m(g){return g===35?(a.consume(g),m):(a.exit("atxHeadingSequence"),h(g))}function p(g){return g===null||g===35||Yt(g)?(a.exit("atxHeadingText"),h(g)):(a.consume(g),p)}}const NS=["address","article","aside","base","basefont","blockquote","body","caption","center","col","colgroup","dd","details","dialog","dir","div","dl","dt","fieldset","figcaption","figure","footer","form","frame","frameset","h1","h2","h3","h4","h5","h6","head","header","hr","html","iframe","legend","li","link","main","menu","menuitem","nav","noframes","ol","optgroup","option","p","param","search","section","summary","table","tbody","td","tfoot","th","thead","title","tr","track","ul"],Om=["pre","script","style","textarea"],zS={concrete:!0,name:"htmlFlow",resolveTo:CS,tokenize:DS},RS={partial:!0,tokenize:jS},OS={partial:!0,tokenize:MS};function CS(a){let n=a.length;for(;n--&&!(a[n][0]==="enter"&&a[n][1].type==="htmlFlow"););return n>1&&a[n-2][1].type==="linePrefix"&&(a[n][1].start=a[n-2][1].start,a[n+1][1].start=a[n-2][1].start,a.splice(n-2,2)),a}function DS(a,n,i){const o=this;let u,s,d,h,m;return p;function p(T){return g(T)}function g(T){return a.enter("htmlFlow"),a.enter("htmlFlowData"),a.consume(T),b}function b(T){return T===33?(a.consume(T),k):T===47?(a.consume(T),s=!0,I):T===63?(a.consume(T),u=3,o.interrupt?n:w):_n(T)?(a.consume(T),d=String.fromCharCode(T),X):i(T)}function k(T){return T===45?(a.consume(T),u=2,S):T===91?(a.consume(T),u=5,h=0,j):_n(T)?(a.consume(T),u=4,o.interrupt?n:w):i(T)}function S(T){return T===45?(a.consume(T),o.interrupt?n:w):i(T)}function j(T){const Re="CDATA[";return T===Re.charCodeAt(h++)?(a.consume(T),h===Re.length?o.interrupt?n:Z:j):i(T)}function I(T){return _n(T)?(a.consume(T),d=String.fromCharCode(T),X):i(T)}function X(T){if(T===null||T===47||T===62||Yt(T)){const Re=T===47,Ye=d.toLowerCase();return!Re&&!s&&Om.includes(Ye)?(u=1,o.interrupt?n(T):Z(T)):NS.includes(d.toLowerCase())?(u=6,Re?(a.consume(T),D):o.interrupt?n(T):Z(T)):(u=7,o.interrupt&&!o.parser.lazy[o.now().line]?i(T):s?G(T):B(T))}return T===45||en(T)?(a.consume(T),d+=String.fromCharCode(T),X):i(T)}function D(T){return T===62?(a.consume(T),o.interrupt?n:Z):i(T)}function G(T){return Ge(T)?(a.consume(T),G):pe(T)}function B(T){return T===47?(a.consume(T),pe):T===58||T===95||_n(T)?(a.consume(T),F):Ge(T)?(a.consume(T),B):pe(T)}function F(T){return T===45||T===46||T===58||T===95||en(T)?(a.consume(T),F):te(T)}function te(T){return T===61?(a.consume(T),q):Ge(T)?(a.consume(T),te):B(T)}function q(T){return T===null||T===60||T===61||T===62||T===96?i(T):T===34||T===39?(a.consume(T),m=T,re):Ge(T)?(a.consume(T),q):ue(T)}function re(T){return T===m?(a.consume(T),m=null,de):T===null||we(T)?i(T):(a.consume(T),re)}function ue(T){return T===null||T===34||T===39||T===47||T===60||T===61||T===62||T===96||Yt(T)?te(T):(a.consume(T),ue)}function de(T){return T===47||T===62||Ge(T)?B(T):i(T)}function pe(T){return T===62?(a.consume(T),le):i(T)}function le(T){return T===null||we(T)?Z(T):Ge(T)?(a.consume(T),le):i(T)}function Z(T){return T===45&&u===2?(a.consume(T),R):T===60&&u===1?(a.consume(T),K):T===62&&u===4?(a.consume(T),ze):T===63&&u===3?(a.consume(T),w):T===93&&u===5?(a.consume(T),W):we(T)&&(u===6||u===7)?(a.exit("htmlFlowData"),a.check(RS,Se,me)(T)):T===null||we(T)?(a.exit("htmlFlowData"),me(T)):(a.consume(T),Z)}function me(T){return a.check(OS,ne,Se)(T)}function ne(T){return a.enter("lineEnding"),a.consume(T),a.exit("lineEnding"),$}function $(T){return T===null||we(T)?me(T):(a.enter("htmlFlowData"),Z(T))}function R(T){return T===45?(a.consume(T),w):Z(T)}function K(T){return T===47?(a.consume(T),d="",fe):Z(T)}function fe(T){if(T===62){const Re=d.toLowerCase();return Om.includes(Re)?(a.consume(T),ze):Z(T)}return _n(T)&&d.length<8?(a.consume(T),d+=String.fromCharCode(T),fe):Z(T)}function W(T){return T===93?(a.consume(T),w):Z(T)}function w(T){return T===62?(a.consume(T),ze):T===45&&u===2?(a.consume(T),w):Z(T)}function ze(T){return T===null||we(T)?(a.exit("htmlFlowData"),Se(T)):(a.consume(T),ze)}function Se(T){return a.exit("htmlFlow"),n(T)}}function MS(a,n,i){const o=this;return u;function u(d){return we(d)?(a.enter("lineEnding"),a.consume(d),a.exit("lineEnding"),s):i(d)}function s(d){return o.parser.lazy[o.now().line]?i(d):n(d)}}function jS(a,n,i){return o;function o(u){return a.enter("lineEnding"),a.consume(u),a.exit("lineEnding"),a.attempt(zo,n,i)}}const LS={name:"htmlText",tokenize:BS};function BS(a,n,i){const o=this;let u,s,d;return h;function h(w){return a.enter("htmlText"),a.enter("htmlTextData"),a.consume(w),m}function m(w){return w===33?(a.consume(w),p):w===47?(a.consume(w),te):w===63?(a.consume(w),B):_n(w)?(a.consume(w),ue):i(w)}function p(w){return w===45?(a.consume(w),g):w===91?(a.consume(w),s=0,j):_n(w)?(a.consume(w),G):i(w)}function g(w){return w===45?(a.consume(w),S):i(w)}function b(w){return w===null?i(w):w===45?(a.consume(w),k):we(w)?(d=b,K(w)):(a.consume(w),b)}function k(w){return w===45?(a.consume(w),S):b(w)}function S(w){return w===62?R(w):w===45?k(w):b(w)}function j(w){const ze="CDATA[";return w===ze.charCodeAt(s++)?(a.consume(w),s===ze.length?I:j):i(w)}function I(w){return w===null?i(w):w===93?(a.consume(w),X):we(w)?(d=I,K(w)):(a.consume(w),I)}function X(w){return w===93?(a.consume(w),D):I(w)}function D(w){return w===62?R(w):w===93?(a.consume(w),D):I(w)}function G(w){return w===null||w===62?R(w):we(w)?(d=G,K(w)):(a.consume(w),G)}function B(w){return w===null?i(w):w===63?(a.consume(w),F):we(w)?(d=B,K(w)):(a.consume(w),B)}function F(w){return w===62?R(w):B(w)}function te(w){return _n(w)?(a.consume(w),q):i(w)}function q(w){return w===45||en(w)?(a.consume(w),q):re(w)}function re(w){return we(w)?(d=re,K(w)):Ge(w)?(a.consume(w),re):R(w)}function ue(w){return w===45||en(w)?(a.consume(w),ue):w===47||w===62||Yt(w)?de(w):i(w)}function de(w){return w===47?(a.consume(w),R):w===58||w===95||_n(w)?(a.consume(w),pe):we(w)?(d=de,K(w)):Ge(w)?(a.consume(w),de):R(w)}function pe(w){return w===45||w===46||w===58||w===95||en(w)?(a.consume(w),pe):le(w)}function le(w){return w===61?(a.consume(w),Z):we(w)?(d=le,K(w)):Ge(w)?(a.consume(w),le):de(w)}function Z(w){return w===null||w===60||w===61||w===62||w===96?i(w):w===34||w===39?(a.consume(w),u=w,me):we(w)?(d=Z,K(w)):Ge(w)?(a.consume(w),Z):(a.consume(w),ne)}function me(w){return w===u?(a.consume(w),u=void 0,$):w===null?i(w):we(w)?(d=me,K(w)):(a.consume(w),me)}function ne(w){return w===null||w===34||w===39||w===60||w===61||w===96?i(w):w===47||w===62||Yt(w)?de(w):(a.consume(w),ne)}function $(w){return w===47||w===62||Yt(w)?de(w):i(w)}function R(w){return w===62?(a.consume(w),a.exit("htmlTextData"),a.exit("htmlText"),n):i(w)}function K(w){return a.exit("htmlTextData"),a.enter("lineEnding"),a.consume(w),a.exit("lineEnding"),fe}function fe(w){return Ge(w)?lt(a,W,"linePrefix",o.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(w):W(w)}function W(w){return a.enter("htmlTextData"),d(w)}}const Wc={name:"labelEnd",resolveAll:HS,resolveTo:VS,tokenize:GS},US={tokenize:YS},IS={tokenize:FS},qS={tokenize:XS};function HS(a){let n=-1;const i=[];for(;++n=3&&(p===null||we(p))?(a.exit("thematicBreak"),n(p)):i(p)}function m(p){return p===u?(a.consume(p),o++,m):(a.exit("thematicBreakSequence"),Ge(p)?lt(a,h,"whitespace")(p):h(p))}}const Gt={continuation:{tokenize:nk},exit:ik,name:"list",tokenize:tk},PS={partial:!0,tokenize:ak},ek={partial:!0,tokenize:lk};function tk(a,n,i){const o=this,u=o.events[o.events.length-1];let s=u&&u[1].type==="linePrefix"?u[2].sliceSerialize(u[1],!0).length:0,d=0;return h;function h(S){const j=o.containerState.type||(S===42||S===43||S===45?"listUnordered":"listOrdered");if(j==="listUnordered"?!o.containerState.marker||S===o.containerState.marker:Bc(S)){if(o.containerState.type||(o.containerState.type=j,a.enter(j,{_container:!0})),j==="listUnordered")return a.enter("listItemPrefix"),S===42||S===45?a.check(vo,i,p)(S):p(S);if(!o.interrupt||S===49)return a.enter("listItemPrefix"),a.enter("listItemValue"),m(S)}return i(S)}function m(S){return Bc(S)&&++d<10?(a.consume(S),m):(!o.interrupt||d<2)&&(o.containerState.marker?S===o.containerState.marker:S===41||S===46)?(a.exit("listItemValue"),p(S)):i(S)}function p(S){return a.enter("listItemMarker"),a.consume(S),a.exit("listItemMarker"),o.containerState.marker=o.containerState.marker||S,a.check(zo,o.interrupt?i:g,a.attempt(PS,k,b))}function g(S){return o.containerState.initialBlankLine=!0,s++,k(S)}function b(S){return Ge(S)?(a.enter("listItemPrefixWhitespace"),a.consume(S),a.exit("listItemPrefixWhitespace"),k):i(S)}function k(S){return o.containerState.size=s+o.sliceSerialize(a.exit("listItemPrefix"),!0).length,n(S)}}function nk(a,n,i){const o=this;return o.containerState._closeFlow=void 0,a.check(zo,u,s);function u(h){return o.containerState.furtherBlankLines=o.containerState.furtherBlankLines||o.containerState.initialBlankLine,lt(a,n,"listItemIndent",o.containerState.size+1)(h)}function s(h){return o.containerState.furtherBlankLines||!Ge(h)?(o.containerState.furtherBlankLines=void 0,o.containerState.initialBlankLine=void 0,d(h)):(o.containerState.furtherBlankLines=void 0,o.containerState.initialBlankLine=void 0,a.attempt(ek,n,d)(h))}function d(h){return o.containerState._closeFlow=!0,o.interrupt=void 0,lt(a,a.attempt(Gt,n,i),"linePrefix",o.parser.constructs.disable.null.includes("codeIndented")?void 0:4)(h)}}function lk(a,n,i){const o=this;return lt(a,u,"listItemIndent",o.containerState.size+1);function u(s){const d=o.events[o.events.length-1];return d&&d[1].type==="listItemIndent"&&d[2].sliceSerialize(d[1],!0).length===o.containerState.size?n(s):i(s)}}function ik(a){a.exit(this.containerState.type)}function ak(a,n,i){const o=this;return lt(a,u,"listItemPrefixWhitespace",o.parser.constructs.disable.null.includes("codeIndented")?void 0:5);function u(s){const d=o.events[o.events.length-1];return!Ge(s)&&d&&d[1].type==="listItemPrefixWhitespace"?n(s):i(s)}}const Cm={name:"setextUnderline",resolveTo:rk,tokenize:ok};function rk(a,n){let i=a.length,o,u,s;for(;i--;)if(a[i][0]==="enter"){if(a[i][1].type==="content"){o=i;break}a[i][1].type==="paragraph"&&(u=i)}else a[i][1].type==="content"&&a.splice(i,1),!s&&a[i][1].type==="definition"&&(s=i);const d={type:"setextHeading",start:{...a[o][1].start},end:{...a[a.length-1][1].end}};return a[u][1].type="setextHeadingText",s?(a.splice(u,0,["enter",d,n]),a.splice(s+1,0,["exit",a[o][1],n]),a[o][1].end={...a[s][1].end}):a[o][1]=d,a.push(["exit",d,n]),a}function ok(a,n,i){const o=this;let u;return s;function s(p){let g=o.events.length,b;for(;g--;)if(o.events[g][1].type!=="lineEnding"&&o.events[g][1].type!=="linePrefix"&&o.events[g][1].type!=="content"){b=o.events[g][1].type==="paragraph";break}return!o.parser.lazy[o.now().line]&&(o.interrupt||b)?(a.enter("setextHeadingLine"),u=p,d(p)):i(p)}function d(p){return a.enter("setextHeadingLineSequence"),h(p)}function h(p){return p===u?(a.consume(p),h):(a.exit("setextHeadingLineSequence"),Ge(p)?lt(a,m,"lineSuffix")(p):m(p))}function m(p){return p===null||we(p)?(a.exit("setextHeadingLine"),n(p)):i(p)}}const sk={tokenize:uk};function uk(a){const n=this,i=a.attempt(zo,o,a.attempt(this.parser.constructs.flowInitial,u,lt(a,a.attempt(this.parser.constructs.flow,u,a.attempt(pS,u)),"linePrefix")));return i;function o(s){if(s===null){a.consume(s);return}return a.enter("lineEndingBlank"),a.consume(s),a.exit("lineEndingBlank"),n.currentConstruct=void 0,i}function u(s){if(s===null){a.consume(s);return}return a.enter("lineEnding"),a.consume(s),a.exit("lineEnding"),n.currentConstruct=void 0,i}}const ck={resolveAll:Hg()},fk=qg("string"),dk=qg("text");function qg(a){return{resolveAll:Hg(a==="text"?hk:void 0),tokenize:n};function n(i){const o=this,u=this.parser.constructs[a],s=i.attempt(u,d,h);return d;function d(g){return p(g)?s(g):h(g)}function h(g){if(g===null){i.consume(g);return}return i.enter("data"),i.consume(g),m}function m(g){return p(g)?(i.exit("data"),s(g)):(i.consume(g),m)}function p(g){if(g===null)return!0;const b=u[g];let k=-1;if(b)for(;++k-1){const h=d[0];typeof h=="string"?d[0]=h.slice(o):d.shift()}s>0&&d.push(a[u].slice(0,s))}return d}function _k(a,n){let i=-1;const o=[];let u;for(;++i0){const rt=ae.tokenStack[ae.tokenStack.length-1];(rt[1]||Mm).call(ae,void 0,rt[0])}for(J.position={start:yl(z.length>0?z[0][1].start:{line:1,column:1,offset:0}),end:yl(z.length>0?z[z.length-2][1].end:{line:1,column:1,offset:0})},Be=-1;++Be0&&(o.className=["language-"+u[0]]);let s={type:"element",tagName:"code",properties:o,children:[{type:"text",value:i}]};return n.meta&&(s.data={meta:n.meta}),a.patch(n,s),s=a.applyData(n,s),s={type:"element",tagName:"pre",properties:{},children:[s]},a.patch(n,s),s}function qk(a,n){const i={type:"element",tagName:"del",properties:{},children:a.all(n)};return a.patch(n,i),a.applyData(n,i)}function Hk(a,n){const i={type:"element",tagName:"em",properties:{},children:a.all(n)};return a.patch(n,i),a.applyData(n,i)}function Vk(a,n){const i=typeof a.options.clobberPrefix=="string"?a.options.clobberPrefix:"user-content-",o=String(n.identifier).toUpperCase(),u=Ii(o.toLowerCase()),s=a.footnoteOrder.indexOf(o);let d,h=a.footnoteCounts.get(o);h===void 0?(h=0,a.footnoteOrder.push(o),d=a.footnoteOrder.length):d=s+1,h+=1,a.footnoteCounts.set(o,h);const m={type:"element",tagName:"a",properties:{href:"#"+i+"fn-"+u,id:i+"fnref-"+u+(h>1?"-"+h:""),dataFootnoteRef:!0,ariaDescribedBy:["footnote-label"]},children:[{type:"text",value:String(d)}]};a.patch(n,m);const p={type:"element",tagName:"sup",properties:{},children:[m]};return a.patch(n,p),a.applyData(n,p)}function Gk(a,n){const i={type:"element",tagName:"h"+n.depth,properties:{},children:a.all(n)};return a.patch(n,i),a.applyData(n,i)}function Yk(a,n){if(a.options.allowDangerousHtml){const i={type:"raw",value:n.value};return a.patch(n,i),a.applyData(n,i)}}function Yg(a,n){const i=n.referenceType;let o="]";if(i==="collapsed"?o+="[]":i==="full"&&(o+="["+(n.label||n.identifier)+"]"),n.type==="imageReference")return[{type:"text",value:"!["+n.alt+o}];const u=a.all(n),s=u[0];s&&s.type==="text"?s.value="["+s.value:u.unshift({type:"text",value:"["});const d=u[u.length-1];return d&&d.type==="text"?d.value+=o:u.push({type:"text",value:o}),u}function Fk(a,n){const i=String(n.identifier).toUpperCase(),o=a.definitionById.get(i);if(!o)return Yg(a,n);const u={src:Ii(o.url||""),alt:n.alt};o.title!==null&&o.title!==void 0&&(u.title=o.title);const s={type:"element",tagName:"img",properties:u,children:[]};return a.patch(n,s),a.applyData(n,s)}function Xk(a,n){const i={src:Ii(n.url)};n.alt!==null&&n.alt!==void 0&&(i.alt=n.alt),n.title!==null&&n.title!==void 0&&(i.title=n.title);const o={type:"element",tagName:"img",properties:i,children:[]};return a.patch(n,o),a.applyData(n,o)}function Qk(a,n){const i={type:"text",value:n.value.replace(/\r?\n|\r/g," ")};a.patch(n,i);const o={type:"element",tagName:"code",properties:{},children:[i]};return a.patch(n,o),a.applyData(n,o)}function Kk(a,n){const i=String(n.identifier).toUpperCase(),o=a.definitionById.get(i);if(!o)return Yg(a,n);const u={href:Ii(o.url||"")};o.title!==null&&o.title!==void 0&&(u.title=o.title);const s={type:"element",tagName:"a",properties:u,children:a.all(n)};return a.patch(n,s),a.applyData(n,s)}function $k(a,n){const i={href:Ii(n.url)};n.title!==null&&n.title!==void 0&&(i.title=n.title);const o={type:"element",tagName:"a",properties:i,children:a.all(n)};return a.patch(n,o),a.applyData(n,o)}function Zk(a,n,i){const o=a.all(n),u=i?Jk(i):Fg(n),s={},d=[];if(typeof n.checked=="boolean"){const g=o[0];let b;g&&g.type==="element"&&g.tagName==="p"?b=g:(b={type:"element",tagName:"p",properties:{},children:[]},o.unshift(b)),b.children.length>0&&b.children.unshift({type:"text",value:" "}),b.children.unshift({type:"element",tagName:"input",properties:{type:"checkbox",checked:n.checked,disabled:!0},children:[]}),s.className=["task-list-item"]}let h=-1;for(;++h1}function Wk(a,n){const i={},o=a.all(n);let u=-1;for(typeof n.start=="number"&&n.start!==1&&(i.start=n.start);++u0){const d={type:"element",tagName:"tbody",properties:{},children:a.wrap(i,!0)},h=Xc(n.children[1]),m=Eg(n.children[n.children.length-1]);h&&m&&(d.position={start:h,end:m}),u.push(d)}const s={type:"element",tagName:"table",properties:{},children:a.wrap(u,!0)};return a.patch(n,s),a.applyData(n,s)}function lw(a,n,i){const o=i?i.children:void 0,s=(o?o.indexOf(n):1)===0?"th":"td",d=i&&i.type==="table"?i.align:void 0,h=d?d.length:n.children.length;let m=-1;const p=[];for(;++m0,!0),o[0]),u=o.index+o[0].length,o=i.exec(n);return s.push(Bm(n.slice(u),u>0,!1)),s.join("")}function Bm(a,n,i){let o=0,u=a.length;if(n){let s=a.codePointAt(o);for(;s===jm||s===Lm;)o++,s=a.codePointAt(o)}if(i){let s=a.codePointAt(u-1);for(;s===jm||s===Lm;)u--,s=a.codePointAt(u-1)}return u>o?a.slice(o,u):""}function rw(a,n){const i={type:"text",value:aw(String(n.value))};return a.patch(n,i),a.applyData(n,i)}function ow(a,n){const i={type:"element",tagName:"hr",properties:{},children:[]};return a.patch(n,i),a.applyData(n,i)}const sw={blockquote:Bk,break:Uk,code:Ik,delete:qk,emphasis:Hk,footnoteReference:Vk,heading:Gk,html:Yk,imageReference:Fk,image:Xk,inlineCode:Qk,linkReference:Kk,link:$k,listItem:Zk,list:Wk,paragraph:Pk,root:ew,strong:tw,table:nw,tableCell:iw,tableRow:lw,text:rw,thematicBreak:ow,toml:co,yaml:co,definition:co,footnoteDefinition:co};function co(){}const Xg=-1,Ro=0,Va=1,To=2,Pc=3,ef=4,tf=5,nf=6,Qg=7,Kg=8,$g=typeof self=="object"?self:globalThis,Um=(a,n)=>{switch(a){case"Function":case"SharedWorker":case"Worker":case"eval":case"setInterval":case"setTimeout":throw new TypeError("unable to deserialize "+a)}return new $g[a](n)},uw=(a,n)=>{const i=(u,s)=>(a.set(s,u),u),o=u=>{if(a.has(u))return a.get(u);const[s,d]=n[u];switch(s){case Ro:case Xg:return i(d,u);case Va:{const h=i([],u);for(const m of d)h.push(o(m));return h}case To:{const h=i({},u);for(const[m,p]of d)h[o(m)]=o(p);return h}case Pc:return i(new Date(d),u);case ef:{const{source:h,flags:m}=d;return i(new RegExp(h,m),u)}case tf:{const h=i(new Map,u);for(const[m,p]of d)h.set(o(m),o(p));return h}case nf:{const h=i(new Set,u);for(const m of d)h.add(o(m));return h}case Qg:{const{name:h,message:m}=d;return i(typeof $g[h]=="function"?Um(h,m):new Error(m),u)}case Kg:return i(BigInt(d),u);case"BigInt":return i(Object(BigInt(d)),u);case"ArrayBuffer":return i(new Uint8Array(d).buffer,d);case"DataView":{const{buffer:h}=new Uint8Array(d);return i(new DataView(h),d)}}return i(Um(s,d),u)};return o},Im=a=>uw(new Map,a)(0),ql="",{toString:cw}={},{keys:fw}=Object,La=a=>{const n=typeof a;if(n!=="object"||!a)return[Ro,n];const i=cw.call(a).slice(8,-1);switch(i){case"Array":return[Va,ql];case"Object":return[To,ql];case"Date":return[Pc,ql];case"RegExp":return[ef,ql];case"Map":return[tf,ql];case"Set":return[nf,ql];case"DataView":return[Va,i]}return i.includes("Array")?[Va,i]:a instanceof Error?[Qg,a.name||"Error"]:[To,i]},fo=([a,n])=>a===Ro&&(n==="function"||n==="symbol"),dw=(a,n,i,o)=>{const u=(d,h)=>{const m=o.push(d)-1;return i.set(h,m),m},s=d=>{if(i.has(d))return i.get(d);let[h,m]=La(d);switch(h){case Ro:{let g=d;switch(m){case"bigint":h=Kg,g=d.toString();break;case"function":case"symbol":if(a)throw new TypeError("unable to serialize "+m);g=null;break;case"undefined":return u([Xg],d)}return u([h,g],d)}case Va:{if(m){let k=d;return m==="DataView"?k=new Uint8Array(d.buffer):m==="ArrayBuffer"&&(k=new Uint8Array(d)),u([m,[...k]],d)}const g=[],b=u([h,g],d);for(const k of d)g.push(s(k));return b}case To:{if(m)switch(m){case"BigInt":return u([m,d.toString()],d);case"Boolean":case"Number":case"String":return u([m,d.valueOf()],d)}if(n&&"toJSON"in d)return s(d.toJSON());const g=[],b=u([h,g],d);for(const k of fw(d))(a||!fo(La(d[k])))&&g.push([s(k),s(d[k])]);return b}case Pc:return u([h,isNaN(d.getTime())?ql:d.toISOString()],d);case ef:{const{source:g,flags:b}=d;return u([h,{source:g,flags:b}],d)}case tf:{const g=[],b=u([h,g],d);for(const[k,S]of d)(a||!(fo(La(k))||fo(La(S))))&&g.push([s(k),s(S)]);return b}case nf:{const g=[],b=u([h,g],d);for(const k of d)(a||!fo(La(k)))&&g.push(s(k));return b}}const{message:p}=d;return u([h,{name:m,message:p}],d)};return s},qm=(a,{json:n,lossy:i}={})=>{const o=[];return dw(!(n||i),!!n,new Map,o)(a),o},Eo=typeof structuredClone=="function"?(a,n)=>n&&("json"in n||"lossy"in n)?Im(qm(a,n)):structuredClone(a):(a,n)=>Im(qm(a,n));function hw(a,n){const i=[{type:"text",value:"↩"}];return n>1&&i.push({type:"element",tagName:"sup",properties:{},children:[{type:"text",value:String(n)}]}),i}function pw(a,n){return"Back to reference "+(a+1)+(n>1?"-"+n:"")}function mw(a){const n=typeof a.options.clobberPrefix=="string"?a.options.clobberPrefix:"user-content-",i=a.options.footnoteBackContent||hw,o=a.options.footnoteBackLabel||pw,u=a.options.footnoteLabel||"Footnotes",s=a.options.footnoteLabelTagName||"h2",d=a.options.footnoteLabelProperties||{className:["sr-only"]},h=[];let m=-1;for(;++m0&&j.push({type:"text",value:" "});let G=typeof i=="string"?i:i(m,S);typeof G=="string"&&(G={type:"text",value:G}),j.push({type:"element",tagName:"a",properties:{href:"#"+n+"fnref-"+k+(S>1?"-"+S:""),dataFootnoteBackref:"",ariaLabel:typeof o=="string"?o:o(m,S),className:["data-footnote-backref"]},children:Array.isArray(G)?G:[G]})}const X=g[g.length-1];if(X&&X.type==="element"&&X.tagName==="p"){const G=X.children[X.children.length-1];G&&G.type==="text"?G.value+=" ":X.children.push({type:"text",value:" "}),X.children.push(...j)}else g.push(...j);const D={type:"element",tagName:"li",properties:{id:n+"fn-"+k},children:a.wrap(g,!0)};a.patch(p,D),h.push(D)}if(h.length!==0)return{type:"element",tagName:"section",properties:{dataFootnotes:!0,className:["footnotes"]},children:[{type:"element",tagName:s,properties:{...Eo(d),id:"footnote-label"},children:[{type:"text",value:u}]},{type:"text",value:` +`},{type:"element",tagName:"ol",properties:{},children:a.wrap(h,!0)},{type:"text",value:` +`}]}}const Zg=(function(a){if(a==null)return xw;if(typeof a=="function")return Oo(a);if(typeof a=="object")return Array.isArray(a)?gw(a):yw(a);if(typeof a=="string")return bw(a);throw new Error("Expected function, string, or object as test")});function gw(a){const n=[];let i=-1;for(;++i":""))+")"})}return k;function k(){let S=Jg,j,I,X;if((!n||s(m,p,g[g.length-1]||void 0))&&(S=Tw(i(m,g)),S[0]===Hm))return S;if("children"in m&&m.children){const D=m;if(D.children&&S[0]!==kw)for(I=(o?D.children.length:-1)+d,X=g.concat(D);I>-1&&I0&&i.push({type:"text",value:` +`}),i}function Vm(a){let n=0,i=a.charCodeAt(n);for(;i===9||i===32;)n++,i=a.charCodeAt(n);return a.slice(n)}function Gm(a,n){const i=_w(a,n),o=i.one(a,void 0),u=mw(i),s=Array.isArray(o)?{type:"root",children:o}:o||{type:"root",children:[]};return u&&s.children.push({type:"text",value:` +`},u),s}function Ow(a,n){return a&&"run"in a?async function(i,o){const u=Gm(i,{file:o,...n});await a.run(u,o)}:function(i,o){return Gm(i,{file:o,...a||n})}}function Ym(a){if(a)throw a}var gc,Fm;function Cw(){if(Fm)return gc;Fm=1;var a=Object.prototype.hasOwnProperty,n=Object.prototype.toString,i=Object.defineProperty,o=Object.getOwnPropertyDescriptor,u=function(p){return typeof Array.isArray=="function"?Array.isArray(p):n.call(p)==="[object Array]"},s=function(p){if(!p||n.call(p)!=="[object Object]")return!1;var g=a.call(p,"constructor"),b=p.constructor&&p.constructor.prototype&&a.call(p.constructor.prototype,"isPrototypeOf");if(p.constructor&&!g&&!b)return!1;var k;for(k in p);return typeof k>"u"||a.call(p,k)},d=function(p,g){i&&g.name==="__proto__"?i(p,g.name,{enumerable:!0,configurable:!0,value:g.newValue,writable:!0}):p[g.name]=g.newValue},h=function(p,g){if(g==="__proto__")if(a.call(p,g)){if(o)return o(p,g).value}else return;return p[g]};return gc=function m(){var p,g,b,k,S,j,I=arguments[0],X=1,D=arguments.length,G=!1;for(typeof I=="boolean"&&(G=I,I=arguments[1]||{},X=2),(I==null||typeof I!="object"&&typeof I!="function")&&(I={});Xd.length;let m;h&&d.push(u);try{m=a.apply(this,d)}catch(p){const g=p;if(h&&i)throw g;return u(g)}h||(m&&m.then&&typeof m.then=="function"?m.then(s,u):m instanceof Error?u(m):s(m))}function u(d,...h){i||(i=!0,n(d,...h))}function s(d){u(null,d)}}const En={basename:Lw,dirname:Bw,extname:Uw,join:Iw,sep:"/"};function Lw(a,n){if(n!==void 0&&typeof n!="string")throw new TypeError('"ext" argument must be a string');Fa(a);let i=0,o=-1,u=a.length,s;if(n===void 0||n.length===0||n.length>a.length){for(;u--;)if(a.codePointAt(u)===47){if(s){i=u+1;break}}else o<0&&(s=!0,o=u+1);return o<0?"":a.slice(i,o)}if(n===a)return"";let d=-1,h=n.length-1;for(;u--;)if(a.codePointAt(u)===47){if(s){i=u+1;break}}else d<0&&(s=!0,d=u+1),h>-1&&(a.codePointAt(u)===n.codePointAt(h--)?h<0&&(o=u):(h=-1,o=d));return i===o?o=d:o<0&&(o=a.length),a.slice(i,o)}function Bw(a){if(Fa(a),a.length===0)return".";let n=-1,i=a.length,o;for(;--i;)if(a.codePointAt(i)===47){if(o){n=i;break}}else o||(o=!0);return n<0?a.codePointAt(0)===47?"/":".":n===1&&a.codePointAt(0)===47?"//":a.slice(0,n)}function Uw(a){Fa(a);let n=a.length,i=-1,o=0,u=-1,s=0,d;for(;n--;){const h=a.codePointAt(n);if(h===47){if(d){o=n+1;break}continue}i<0&&(d=!0,i=n+1),h===46?u<0?u=n:s!==1&&(s=1):u>-1&&(s=-1)}return u<0||i<0||s===0||s===1&&u===i-1&&u===o+1?"":a.slice(u,i)}function Iw(...a){let n=-1,i;for(;++n0&&a.codePointAt(a.length-1)===47&&(i+="/"),n?"/"+i:i}function Hw(a,n){let i="",o=0,u=-1,s=0,d=-1,h,m;for(;++d<=a.length;){if(d2){if(m=i.lastIndexOf("/"),m!==i.length-1){m<0?(i="",o=0):(i=i.slice(0,m),o=i.length-1-i.lastIndexOf("/")),u=d,s=0;continue}}else if(i.length>0){i="",o=0,u=d,s=0;continue}}n&&(i=i.length>0?i+"/..":"..",o=2)}else i.length>0?i+="/"+a.slice(u+1,d):i=a.slice(u+1,d),o=d-u-1;u=d,s=0}else h===46&&s>-1?s++:s=-1}return i}function Fa(a){if(typeof a!="string")throw new TypeError("Path must be a string. Received "+JSON.stringify(a))}const Vw={cwd:Gw};function Gw(){return"/"}function Hc(a){return!!(a!==null&&typeof a=="object"&&"href"in a&&a.href&&"protocol"in a&&a.protocol&&a.auth===void 0)}function Yw(a){if(typeof a=="string")a=new URL(a);else if(!Hc(a)){const n=new TypeError('The "path" argument must be of type string or an instance of URL. Received `'+a+"`");throw n.code="ERR_INVALID_ARG_TYPE",n}if(a.protocol!=="file:"){const n=new TypeError("The URL must be of scheme file");throw n.code="ERR_INVALID_URL_SCHEME",n}return Fw(a)}function Fw(a){if(a.hostname!==""){const o=new TypeError('File URL host must be "localhost" or empty on darwin');throw o.code="ERR_INVALID_FILE_URL_HOST",o}const n=a.pathname;let i=-1;for(;++i0){let[S,...j]=g;const I=o[k][1];qc(I)&&qc(S)&&(S=yc(!0,I,S)),o[k]=[p,S,...j]}}}}const $w=new lf().freeze();function Sc(a,n){if(typeof n!="function")throw new TypeError("Cannot `"+a+"` without `parser`")}function kc(a,n){if(typeof n!="function")throw new TypeError("Cannot `"+a+"` without `compiler`")}function wc(a,n){if(n)throw new Error("Cannot call `"+a+"` on a frozen processor.\nCreate a new processor first, by calling it: use `processor()` instead of `processor`.")}function Qm(a){if(!qc(a)||typeof a.type!="string")throw new TypeError("Expected node, got `"+a+"`")}function Km(a,n,i){if(!i)throw new Error("`"+a+"` finished async. Use `"+n+"` instead")}function ho(a){return Zw(a)?a:new Pg(a)}function Zw(a){return!!(a&&typeof a=="object"&&"message"in a&&"messages"in a)}function Jw(a){return typeof a=="string"||Ww(a)}function Ww(a){return!!(a&&typeof a=="object"&&"byteLength"in a&&"byteOffset"in a)}const Pw="https://github.com/remarkjs/react-markdown/blob/main/changelog.md",$m=[],Zm={allowDangerousHtml:!0},eT=/^(https?|ircs?|mailto|xmpp)$/i,tT=[{from:"astPlugins",id:"remove-buggy-html-in-markdown-parser"},{from:"allowDangerousHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"allowNode",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowElement"},{from:"allowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"allowedElements"},{from:"className",id:"remove-classname"},{from:"disallowedTypes",id:"replace-allownode-allowedtypes-and-disallowedtypes",to:"disallowedElements"},{from:"escapeHtml",id:"remove-buggy-html-in-markdown-parser"},{from:"includeElementIndex",id:"#remove-includeelementindex"},{from:"includeNodeIndex",id:"change-includenodeindex-to-includeelementindex"},{from:"linkTarget",id:"remove-linktarget"},{from:"plugins",id:"change-plugins-to-remarkplugins",to:"remarkPlugins"},{from:"rawSourcePos",id:"#remove-rawsourcepos"},{from:"renderers",id:"change-renderers-to-components",to:"components"},{from:"source",id:"change-source-to-children",to:"children"},{from:"sourcePos",id:"#remove-sourcepos"},{from:"transformImageUri",id:"#add-urltransform",to:"urlTransform"},{from:"transformLinkUri",id:"#add-urltransform",to:"urlTransform"}];function nT(a){const n=lT(a),i=iT(a);return aT(n.runSync(n.parse(i),i),a)}function lT(a){const n=a.rehypePlugins||$m,i=a.remarkPlugins||$m,o=a.remarkRehypeOptions?{...a.remarkRehypeOptions,...Zm}:Zm;return $w().use(Lk).use(i).use(Ow,o).use(n)}function iT(a){const n=a.children||"",i=new Pg;return typeof n=="string"&&(i.value=n),i}function aT(a,n){const i=n.allowedElements,o=n.allowElement,u=n.components,s=n.disallowedElements,d=n.skipHtml,h=n.unwrapDisallowed,m=n.urlTransform||rT;for(const g of tT)Object.hasOwn(n,g.from)&&(""+g.from+(g.to?"use `"+g.to+"` instead":"remove it")+Pw+g.id,void 0);return Wg(a,p),mv(a,{Fragment:v.Fragment,components:u,ignoreInvalidStyle:!0,jsx:v.jsx,jsxs:v.jsxs,passKeys:!0,passNode:!0});function p(g,b,k){if(g.type==="raw"&&k&&typeof b=="number")return d?k.children.splice(b,1):k.children[b]={type:"text",value:g.value},b;if(g.type==="element"){let S;for(S in hc)if(Object.hasOwn(hc,S)&&Object.hasOwn(g.properties,S)){const j=g.properties[S],I=hc[S];(I===null||I.includes(g.tagName))&&(g.properties[S]=m(String(j||""),S,g))}}if(g.type==="element"){let S=i?!i.includes(g.tagName):s?s.includes(g.tagName):!1;if(!S&&o&&typeof b=="number"&&(S=!o(g,b,k)),S&&k&&typeof b=="number")return h&&g.children?k.children.splice(b,1,...g.children):k.children.splice(b,1),b}}}function rT(a){const n=a.indexOf(":"),i=a.indexOf("?"),o=a.indexOf("#"),u=a.indexOf("/");return n===-1||u!==-1&&n>u||i!==-1&&n>i||o!==-1&&n>o||eT.test(a.slice(0,n))?a:""}const Tc=4e3,oT=["a","blockquote","br","code","em","h1","h2","h3","h4","h5","h6","hr","li","ol","p","pre","strong","ul"],ey=L.memo(({source:a})=>v.jsx(nT,{allowedElements:oT,skipHtml:!0,children:a}));ey.displayName="MarkdownChunk";function sT({children:a,className:n,expandable:i,sourceCharacterBudget:o}){const[u,s]=L.useState(1),d=[];for(let m=0;ms(m=>m+1),children:"Show more"})]})}function uT(a){return v.jsx(sT,{...a},a.sourceCharacterBudget)}function Ec({children:a,className:n,expandable:i=!0,sourceCharacterBudget:o=Tc}){const u=Number.isFinite(o)?Math.min(Tc,Math.max(1,Math.floor(o))):Tc;return v.jsx(uT,{className:n,expandable:i,sourceCharacterBudget:u,children:a},a)}const _c=100,ty=240,af=12;function Bi(a,n,i=`${n}s`){return a===1?n:i}function ny(a){const n=[];for(const i in a)Object.prototype.hasOwnProperty.call(a,i)&&n.push([i,a[i]]);return n}function rf(a){return Array.isArray(a)?a.length:ny(a).length}function ly(a){const n=rf(a);return Array.isArray(a)?`[${n} ${Bi(n,"item")}]`:`{${n} ${Bi(n,"property","properties")}}`}function cT({value:a}){const[n,i]=L.useState(!1),o=L.useId();return v.jsxs("span",{className:"value-long-string inline",children:[v.jsx("span",{className:"value-string whitespace-pre-wrap text-mint [overflow-wrap:anywhere]",id:o,children:n?a:`${a.slice(0,ty)}…`})," ",v.jsx("button",{type:"button",className:"value-string-action cursor-pointer border-0 bg-transparent p-0 text-left font-mono text-[9px]/[1.45] text-acid","aria-controls":o,"aria-expanded":n,onClick:()=>i(u=>!u),children:n?"Show less":"Show full string"})]})}function iy({value:a}){const n=rf(a),i=Array.isArray(a)?Bi(n,"item"):Bi(n,"property","properties"),o=`${n} ${i}. Deeper values are not shown (maximum depth ${af}).`;return v.jsxs("span",{className:"value-truncated text-muted",role:"note","aria-label":o,children:[ly(a)," · maximum depth reached"]})}function ay({value:a}){if(a===null)return v.jsx("span",{className:"value-null text-muted",children:"null"});if(typeof a=="string")return a.length>ty?v.jsx(cT,{value:a}):v.jsx("span",{className:"value-string whitespace-pre-wrap text-mint [overflow-wrap:anywhere]",children:a});if(typeof a=="number"||typeof a=="boolean")return v.jsx("span",{className:"value-scalar text-acid",children:String(a)});if(mn(a)){if(a.kind==="predict_rlm_file"&&typeof a.path=="string")return v.jsxs("span",{className:"file-value flex min-w-48 gap-[9px] rounded-[7px] border border-acid p-[9px] text-acid [&_small]:block [&_small]:text-[7px] [&_small]:text-muted [&_small]:uppercase [&_code]:mt-[3px] [&_code]:block [&_code]:whitespace-normal [&_code]:text-[9px] [&_code]:[overflow-wrap:anywhere]",title:"Reported host path; contents are not copied",children:[v.jsx("span",{"aria-hidden":"true",children:"↗"}),v.jsxs("span",{children:[v.jsx("small",{children:"PredictRLM file"}),v.jsx("code",{children:a.path})]})]});if(a.kind==="unavailable"&&typeof a.reason=="string")return v.jsxs("span",{className:"value-unavailable text-[9px] text-amber",children:["Unavailable · ",a.reason]})}return v.jsx("span",{className:"value-unavailable text-[9px] text-amber",children:"Unavailable"})}function ry(a){return Array.isArray(a)||mn(a)&&!(a.kind==="predict_rlm_file"&&typeof a.path=="string"||a.kind==="unavailable"&&typeof a.reason=="string")}function fT({label:a,value:n,depth:i,path:o,onExpand:u}){const[s,d]=L.useState(!1),h=L.useId();return i>=af?v.jsx(iy,{value:n}):v.jsxs("div",{className:"value-collection min-w-0",children:[v.jsxs("button",{type:"button",className:"value-disclosure inline-flex cursor-pointer items-baseline gap-[5px] border-0 bg-transparent p-0 text-left font-mono text-[9px]/[1.45] text-acid","aria-controls":h,"aria-expanded":s,"aria-label":`${s?"Collapse":"Expand"} ${a}`,onClick:()=>{s||u?.(n,o),d(p=>!p)},children:[v.jsx("span",{"aria-hidden":"true",children:s?"▾":"▸"}),v.jsx("span",{children:ly(n)})]}),s&&v.jsx("div",{className:"value-child-group mt-[5px] min-w-80 border-l border-line pl-3",id:h,role:"group",children:v.jsx(oy,{value:n,depth:i,path:o,onExpand:u})})]})}function oy({value:a,depth:n,path:i,onExpand:o}){const[u,s]=L.useState(_c),d=Array.isArray(a)?a.slice(0,u).map((g,b)=>[b,g]):ny(a).slice(0,u),h=rf(a),m=h-d.length,p=Math.min(_c,m);return h?v.jsxs(v.Fragment,{children:[v.jsx("ul",{className:"value-group m-0 min-w-80 list-none p-0",role:"group",children:d.map(([g,b])=>{const k=[...i,g],S=ry(b);return v.jsx("li",{className:"value-tree-item min-w-0 border-t border-line first:border-t-0",role:"treeitem",children:v.jsxs("div",{className:"value-row grid min-w-80 grid-cols-[fit-content(12rem)_.55rem_minmax(12rem,1fr)] items-start gap-x-0.5 py-[7px]",children:[v.jsx("span",{className:"value-key min-w-0 font-mono text-[9px]/[1.45] text-muted [overflow-wrap:anywhere]",children:Array.isArray(a)?`[${g}]`:g}),v.jsx("span",{className:"value-separator text-center text-muted","aria-hidden":"true",children:":"}),v.jsx("div",{className:"value-content min-w-48 [overflow-wrap:anywhere]",children:S?v.jsx(fT,{label:String(g),value:b,depth:n+1,path:k,onExpand:o}):v.jsx(ay,{value:b})})]})},`${typeof g}:${String(g)}`)})}),m>0&&v.jsxs("button",{type:"button",className:"value-more my-2 cursor-pointer border-0 bg-transparent p-0 text-left font-mono text-[9px]/[1.45] text-acid",onClick:()=>s(g=>g+_c),children:["Show ",p," more ",Array.isArray(a)?Bi(p,"item"):Bi(p,"property","properties")]})]}):v.jsx("span",{className:"value-empty-collection text-muted",children:Array.isArray(a)?"[]":"{}"})}function Ba({value:a,depth:n=0,onExpand:i}){return ry(a)?n>=af?v.jsx(iy,{value:a}):v.jsx("div",{className:"value-tree min-w-0 max-w-full overflow-x-auto text-[10px]",role:"tree","aria-label":"JSON value",children:v.jsx(oy,{value:a,depth:n,path:[],onExpand:i})}):v.jsx(ay,{value:a})}const dT=8,sy=[],po={records:sy,nextPageToken:"",nextCursor:"0"};function mo(a){if(a)try{return JSON.parse(a)}catch{return}}function hT(a){if(mn(a))return mn(a.data)?a.data:a}function Jm(a){return{event:a.eventKind,event_sequence:a.eventSequence,invocation_id:a.invocationId,iteration:a.iteration,duration_ms:a.durationMs,tool_count:a.toolCount,predict_count:a.predictCount,failed:a.error}}function pT({api:a,workflow:n,run:i,nodeId:o,liveEvents:u=sy,onClose:s}){const[d,h]=L.useState(),[m,p]=L.useState(po),[g,b]=L.useState(),[k,S]=L.useState(),[j,I]=L.useState(!1),[X,D]=L.useState(!0),[G,B]=L.useState(0),[F,te]=L.useState({}),[q,re]=L.useState(0),[ue,de]=L.useState(),pe=L.useRef(new Map),le=L.useRef(new Set),Z=L.useRef(new Set),me=L.useRef(null),ne=L.useRef(!1),$=L.useRef(0),R=L.useRef(0),K=L.useRef(null),fe=L.useRef("overview"),W=i?.nodes.find(Q=>Q.nodeId===o),w=i?.summary?.runId,ze=i?.operatorInstanceId??"",Se=i?.asOfSequence??"",T=W?.eventPageToken??"",Re=!!(i&&W),Ye=`${ze}\0${w??""}\0${o??""}`,Le=`${Ye}\0${Se}\0${T}`,ke=d?.scope===Ye?d.tab:"overview",Ke=`${Le}\0${ke}`,We=ke==="output"?Mt.NEWEST_FIRST:Mt.FORWARD,Ie=g===Ke?m:po,Pe=i?void 0:dg(n?.agentMetadataJson[o??""]),St=i?hg(i.topology?.agentFieldSchemasJson[o??""]):void 0;fe.current=ke;const Tt=L.useCallback(()=>{R.current+=1;for(const Q of Z.current)Q.abort();Z.current.clear(),le.current.clear()},[]);L.useEffect(()=>()=>{Tt()},[Tt]);function nt(){Tt(),s()}function jt(Q,se){return`${Q}\0${se}`}function gn(Q,se,oe){const be=Ia(se,oe);if(be>ji)return!1;pe.current.delete(Q),pe.current.set(Q,{value:se,byteCost:be});let Oe=0;for(const Fe of pe.current.values())Oe+=Fe.byteCost;for(;pe.current.size>dT||Oe>ji;){const Fe=pe.current.entries().next().value;if(!Fe)break;pe.current.delete(Fe[0]),Oe-=Fe[1].byteCost}return B(Fe=>Fe+1),!0}function tn(){if(!Ie.nextPageToken||!o||!w||ne.current)return;me.current?.abort();const Q=++$.current,se=new AbortController;me.current=se,ne.current=!0,S(void 0),I(!0),a.listAgentEventPage({pageToken:Ie.nextPageToken,afterEventSequence:We===Mt.FORWARD?Ie.nextCursor:"0",beforeEventSequence:We===Mt.NEWEST_FIRST?Ie.nextCursor:"0",pageSize:ko,order:We,expectedOperatorInstanceId:ze,expectedAsOfSequence:Se,expectedRunId:w,expectedNodeId:o},se.signal).then(oe=>{se.signal.aborted||$.current!==Q||p(be=>yg(be,oe,Oe=>Oe.eventSequence,We===Mt.FORWARD?"newer":"older",st?[st.eventSequence]:[]))}).catch(oe=>{se.signal.aborted||$.current!==Q||S({key:Ke,value:oe instanceof Error?oe.message:"Events unavailable"})}).finally(()=>{se.signal.aborted||$.current!==Q||(ne.current=!1,I(!1))})}L.useEffect(()=>{h({scope:Ye,tab:"overview"})},[Ye]),L.useEffect(()=>{me.current?.abort(),ne.current=!1,Tt(),$.current+=1,p(po),b(void 0),S(void 0),I(!1),D(!0),te({}),de(void 0),pe.current.clear(),le.current.clear()},[Tt,a,Le]),L.useEffect(()=>{Tt(),re(Q=>Q+1)},[Tt,Le,ke]),L.useEffect(()=>{me.current?.abort(),ne.current=!1;const Q=++$.current;if(p(po),b(void 0),S(void 0),I(!1),!Re||!o||!w||ke==="overview")return;const se=new AbortController;return me.current=se,T?(ne.current=!0,I(!0),a.listAgentEventPage({pageToken:T,afterEventSequence:"0",beforeEventSequence:"0",pageSize:ko,order:We,expectedOperatorInstanceId:ze,expectedAsOfSequence:Se,expectedRunId:w,expectedNodeId:o},se.signal).then(oe=>{se.signal.aborted||$.current!==Q||(p(oe),b(Ke))}).catch(oe=>{se.signal.aborted||$.current!==Q||S({key:Ke,value:oe instanceof Error?oe.message:"Events unavailable"})}).finally(()=>{se.signal.aborted||$.current!==Q||(ne.current=!1,I(!1))}),()=>{se.abort(),me.current===se&&(ne.current=!1)}):(b(Ke),()=>se.abort())},[a,Se,Le,We,T,Re,o,ze,Ke,w,ke]);const Ot=L.useMemo(()=>{const Q=new Map,se=new Set;for(const oe of Ie.records)Q.set(oe.eventSequence,oe);for(const oe of u)Q.set(oe.eventSequence,oe),se.add(oe.eventSequence);return Gc(Q,oe=>oe.eventSequence,We===Mt.FORWARD?"newer":"older",se)},[Ie.records,We,u]),Et=L.useMemo(()=>Ot.filter(Q=>Q.eventKind==="iteration.recorded"),[Ot]),st=L.useMemo(()=>{if(ke!=="inputs"&&ke!=="output")return;const Q=ke==="inputs"?"run.started":"run.succeeded";return[...Ot].reverse().find(se=>se.eventKind===Q)},[Ot,ke]),xt=st?`${Le}\0${ke}\0${st.bodyToken}`:void 0;L.useEffect(()=>{if(ke!=="inputs"&&ke!=="output"||!st||!xt){de(void 0);return}const Q=jt("json",st.bodyToken),se=pe.current.get(Q);if(se){pe.current.delete(Q),pe.current.set(Q,se),de({key:xt,status:"ready"});return}const oe=R.current,be=new AbortController;return Z.current.add(be),de({key:xt,status:"loading"}),a.readJsonDetail(st.bodyToken,be.signal).then(Oe=>{if(!(be.signal.aborted||R.current!==oe||fe.current!==ke)){if(!gn(Q,Oe,st.sizeBytes)){de({key:xt,status:"error",error:"Retained value exceeds the browser detail limit."});return}de({key:xt,status:"ready"})}}).catch(Oe=>{be.signal.aborted||R.current!==oe||de({key:xt,status:"error",error:Oe instanceof Error?Oe.message:"Detail unavailable"})}).finally(()=>Z.current.delete(be)),()=>{be.abort(),Z.current.delete(be)}},[a,G,Le,ke,xt,st]);function vl(Q){if(fe.current!=="trace")return;const se=jt("json",Q.bodyToken);if(pe.current.has(se)||le.current.has(se))return;const oe=R.current,be=new AbortController;Z.current.add(be),le.current.add(se),te(Oe=>{if(!(se in Oe))return Oe;const Fe={...Oe};return delete Fe[se],Fe}),re(Oe=>Oe+1),a.readJsonDetail(Q.bodyToken,be.signal).then(Oe=>{be.signal.aborted||R.current!==oe||fe.current!=="trace"||gn(se,Oe,Q.sizeBytes)||te(Fe=>({...Fe,[se]:"Turn detail exceeds the browser detail limit."}))}).catch(Oe=>{be.signal.aborted||R.current!==oe||te(Fe=>({...Fe,[se]:Oe instanceof Error?Oe.message:"Turn detail unavailable"}))}).finally(()=>{Z.current.delete(be),le.current.delete(se),!(be.signal.aborted||R.current!==oe)&&re(Oe=>Oe+1)})}const vn=L.useMemo(()=>{const Q=new WeakMap,se=Et.map(oe=>{const be=jt("json",oe.bodyToken),Oe=pe.current.get(be)?.value,Fe=F[be],Co=le.current.has(be),Sl={...Jm(oe),...mn(Oe)?Oe:Oe!==void 0?{detail:Oe}:{detail:Fe?{kind:"unavailable",reason:Fe}:Co?"Loading retained turn…":"Expand this turn to load its retained detail."}};return Q.set(Sl,oe),Sl});return{descriptors:Q,values:se}},[G,F,q,Et]),ie=L.useMemo(()=>{const Q=W?.trace?.header;return{status:W?.trace?.status,complete:W?.trace?.complete,event_count:W?.trace?.eventCount,size_bytes:W?.trace?.sizeBytes,model:Q?.model,sub_model:Q?.subModel,iterations:Q?.iterations,max_iterations:Q?.maxIterations,duration_ms:Q?.durationMs,usage:mo(Q?.usageJson),telemetry:mo(Q?.telemetryJson),lifecycle:Ot.filter(se=>se.eventKind!=="iteration.recorded").map(Jm),turns:vn.values}},[Ot,W?.trace,vn.values]);if(L.useEffect(()=>{ke!=="trace"||!X||!Et.length||!K.current||(K.current.scrollTop=K.current.scrollHeight)},[X,ke,Et.length]),!i&&n&&o)return v.jsxs("aside",{className:"inspector inspector-declaration fixed top-[58px] right-0 bottom-0 z-30 grid h-full w-[min(var(--workspace-inspector-width),100vw)] min-h-0 min-w-0 grid-rows-[auto_minmax(0,1fr)] overflow-hidden border-l border-line bg-panel shadow-[-20px_0_50px_rgba(20,31,26,.14)] min-[1001px]:static min-[1001px]:z-auto min-[1001px]:w-auto min-[1001px]:shadow-none max-[700px]:w-screen","aria-label":"Node declaration",children:[v.jsxs("header",{className:"flex items-start justify-between border-b border-line px-5 pt-[19px] pb-3.5",children:[v.jsxs("div",{children:[v.jsx("span",{className:"eyebrow block font-mono text-[9px] tracking-[.16em] text-acid uppercase",children:"Declaration"}),v.jsx("h2",{className:"mt-1 mb-[5px] text-lg",children:n.displayNames[o]||o})]}),v.jsx("button",{type:"button",className:"icon-button grid size-[30px] cursor-pointer place-items-center rounded-[7px] border border-line bg-panel p-0 text-secondary hover:border-secondary hover:bg-panel hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-acid",onClick:nt,"aria-label":"Close",children:v.jsx(Rc,{"aria-hidden":"true",className:"size-4",strokeWidth:1.8})})]}),Pe?v.jsxs("div",{className:"inspector-body inspector-body-full declaration h-full min-h-0 min-w-0 overflow-auto px-5 pt-[18px] pb-[30px] [&>section]:mb-[23px] [&_h3]:text-[10px] [&_h3]:tracking-[.08em] [&_h3]:text-secondary [&_h3]:uppercase",children:[v.jsxs("section",{children:[v.jsx("h3",{children:"Instructions"}),v.jsx(Ec,{className:"instructions text-xs leading-[1.65] whitespace-normal text-secondary [&>:first-child]:mt-0 [&>:last-child]:mb-0",children:Pe.instructions||"No instructions"})]}),v.jsxs("section",{className:"signature-columns grid grid-cols-[minmax(0,1fr)_minmax(0,1fr)] gap-3",children:[v.jsxs("div",{children:[v.jsx("h3",{children:"Inputs"}),Pe.inputs.map(Q=>v.jsxs("div",{className:"field-detail border-t border-line py-2 [&_strong]:block [&_strong]:text-[10px] [&_code]:mt-0.5 [&_code]:block [&_code]:text-[8px] [&_code]:text-muted [&_code]:[overflow-wrap:anywhere] [&_p]:mt-1 [&_p]:mb-0 [&_p]:text-[9px] [&_p]:text-muted [&_p]:[overflow-wrap:anywhere]",children:[v.jsx("strong",{children:Q.name}),v.jsx("code",{children:Q.type}),Q.description&&v.jsx("p",{children:Q.description})]},Q.name))]}),v.jsxs("div",{children:[v.jsx("h3",{children:"Outputs"}),Pe.outputs.map(Q=>v.jsxs("div",{className:"field-detail border-t border-line py-2 [&_strong]:block [&_strong]:text-[10px] [&_code]:mt-0.5 [&_code]:block [&_code]:text-[8px] [&_code]:text-muted [&_code]:[overflow-wrap:anywhere] [&_p]:mt-1 [&_p]:mb-0 [&_p]:text-[9px] [&_p]:text-muted [&_p]:[overflow-wrap:anywhere]",children:[v.jsx("strong",{children:Q.name}),v.jsx("code",{children:Q.type}),Q.description&&v.jsx("p",{children:Q.description})]},Q.name))]})]}),Pe.runtime!==void 0&&v.jsxs("section",{children:[v.jsx("h3",{children:"Runtime"}),v.jsx(Ba,{value:Pe.runtime})]}),Pe.model!==void 0&&v.jsxs("section",{children:[v.jsx("h3",{children:"Models"}),v.jsx(Ba,{value:Pe.model})]}),(Pe.skills.length>0||Pe.tools.length>0)&&v.jsxs("section",{className:"inspector-declaration-resources grid gap-3",children:[v.jsx("h3",{children:"Skills & tools"}),Pe.skills.map(Q=>v.jsxs("article",{className:"inspector-declaration-resource min-w-0 border-t border-line pt-2 text-[10px] leading-[1.55] text-secondary [&>strong]:inline [&>span]:ml-1.5 [&>span]:font-mono [&>span]:text-[8px] [&>span]:text-muted [&>span]:uppercase [&>div]:mt-1.5 [&>div]:[overflow-wrap:anywhere] [&>div>:last-child]:mb-0",children:[v.jsx("strong",{children:Q.name}),v.jsx("span",{children:"Skill"}),v.jsx(Ec,{children:Q.instructions})]},`skill-${Q.name}`)),Pe.tools.map(Q=>v.jsxs("article",{className:"inspector-declaration-resource min-w-0 border-t border-line pt-2 text-[10px] leading-[1.55] text-secondary [&>strong]:inline [&>span]:ml-1.5 [&>span]:font-mono [&>span]:text-[8px] [&>span]:text-muted [&>span]:uppercase [&>div]:mt-1.5 [&>div]:[overflow-wrap:anywhere] [&>div>:last-child]:mb-0",children:[v.jsx("strong",{children:Q.name}),v.jsx("span",{children:"Tool"}),v.jsx(Ec,{children:Q.description})]},`tool-${Q.name}`))]})]}):v.jsx("p",{className:"empty-copy text-[11px] text-muted",children:"This node has no agent declaration metadata."})]});if(!i||!W)return null;const ce=ke==="inputs"?St?.inputs:ke==="output"?St?.outputs:void 0,z=st?pe.current.get(jt("json",st.bodyToken)):void 0,J=hT(z?.value),ae=ke==="inputs"?"inputs":"outputs",ye=k?.key===Ke?k.value:void 0,Be=xt!==void 0&&ue?.key===xt?ue:void 0,rt=!ye&&(g!==Ke||xt!==void 0&&z===void 0&&Be?.status!=="error"),ht=Be?.status==="error"?Be.error:void 0;return v.jsxs("aside",{className:"inspector inspector-run fixed top-[58px] right-0 bottom-0 z-30 grid h-full w-[min(var(--workspace-inspector-width),100vw)] min-h-0 min-w-0 grid-rows-[auto_auto_minmax(0,1fr)] overflow-hidden border-l border-line bg-panel shadow-[-20px_0_50px_rgba(20,31,26,.14)] min-[1001px]:static min-[1001px]:z-auto min-[1001px]:w-auto min-[1001px]:shadow-none max-[700px]:w-screen","aria-label":"Run inspector",children:[v.jsxs("header",{className:"flex items-start justify-between border-b border-line px-5 pt-[19px] pb-3.5",children:[v.jsxs("div",{children:[v.jsx("span",{className:"eyebrow block font-mono text-[9px] tracking-[.16em] text-acid uppercase",children:"Execution detail"}),v.jsx("h2",{className:"mt-1 mb-[5px] text-lg",children:W.name}),v.jsx("span",{className:`status-pill inline-flex rounded-full border bg-panel px-[7px] py-[3px] font-mono text-[8px] uppercase ${W.status==="failed"?"status-failed border-danger text-danger":W.status==="success"?"status-success border-mint text-mint":"border-line text-muted"}`,children:W.status})]}),v.jsx("button",{type:"button",className:"icon-button grid size-[30px] cursor-pointer place-items-center rounded-[7px] border border-line bg-panel p-0 text-secondary hover:border-secondary hover:bg-panel hover:text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-acid",onClick:nt,"aria-label":"Close",children:v.jsx(Rc,{"aria-hidden":"true",className:"size-4",strokeWidth:1.8})})]}),v.jsx("nav",{className:"inspector-tabs flex overflow-x-auto border-b border-line px-2.5","aria-label":"Run detail views",children:["overview","inputs","output","trace"].map(Q=>v.jsx("button",{type:"button",className:`flex-[1_0_auto] cursor-pointer border-0 border-b-2 bg-transparent px-[9px] pt-[11px] pb-[9px] font-mono text-[8px] uppercase focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-acid ${ke===Q?"active border-acid text-acid":"border-transparent text-muted"}`,"aria-current":ke===Q?"page":void 0,onClick:()=>h({scope:Ye,tab:Q}),children:Q},Q))}),v.jsxs("div",{className:"inspector-body inspector-body-full h-full min-h-0 min-w-0 overflow-auto px-5 pt-[18px] pb-[30px] [&>section]:mb-[23px] [&_h3]:text-[10px] [&_h3]:tracking-[.08em] [&_h3]:text-secondary [&_h3]:uppercase",children:[ke==="overview"&&v.jsxs("section",{className:"inspector-panel inspector-overview min-h-full min-w-0",children:[v.jsxs("div",{className:"metric-grid grid grid-cols-2 gap-2 [&>div]:rounded-[7px] [&>div]:border [&>div]:border-line [&>div]:bg-panel [&>div]:p-2.5 [&_small]:block [&_small]:text-[7px] [&_small]:text-muted [&_small]:uppercase [&_strong]:mt-[5px] [&_strong]:block [&_strong]:text-[11px]",children:[v.jsxs("div",{children:[v.jsx("small",{children:"Status"}),v.jsx("strong",{children:W.status})]}),v.jsxs("div",{children:[v.jsx("small",{children:"Started"}),v.jsx("strong",{children:W.startedAt?"yes":"—"})]}),v.jsxs("div",{children:[v.jsx("small",{children:"Duration"}),v.jsx("strong",{children:W.startedAt&&W.endedAt?`${Math.max(0,W.endedAt-W.startedAt).toFixed(2)}s`:"—"})]})]}),W.error&&v.jsx("p",{className:"node-failure rounded-[7px] border border-danger p-2.5 text-[10px] text-danger [overflow-wrap:anywhere]",children:W.error}),W.trace&&v.jsxs("section",{children:[v.jsx("h3",{children:"Trace summary"}),v.jsx(Ba,{value:{status:W.trace.status,events:W.trace.eventCount,size_bytes:W.trace.sizeBytes,complete:W.trace.complete,model:W.trace.header?.model,iterations:W.trace.header?`${W.trace.header.iterations}/${W.trace.header.maxIterations}`:void 0,duration_ms:W.trace.header?.durationMs,usage:mo(W.trace.header?.usageJson),telemetry:mo(W.trace.header?.telemetryJson)}})]})]}),(ke==="inputs"||ke==="output")&&v.jsxs("section",{className:"inspector-panel inspector-value-panel min-h-full min-w-0",children:[v.jsx("h3",{children:ke==="inputs"?"Invocation inputs":"Terminal output"}),ce?.length?v.jsxs("div",{className:"declared-fields mb-2.5 flex flex-wrap gap-[5px] [&>small]:w-full [&>small]:text-[8px] [&>small]:text-muted [&>small]:uppercase [&>span]:inline-flex [&>span]:gap-[5px] [&>span]:rounded-[5px] [&>span]:border [&>span]:border-line [&>span]:bg-panel [&>span]:px-1.5 [&>span]:py-1 [&>span]:text-[9px] [&_code]:text-secondary",children:[v.jsx("small",{children:"Declared fields"}),ce.map(Q=>v.jsxs("span",{children:[v.jsx("strong",{children:Q.name}),v.jsx("code",{children:Q.type})]},Q.name))]}):null,ye&&v.jsx("p",{className:"inspector-error rounded-[7px] border border-danger p-2.5 text-[10px] text-danger [overflow-wrap:anywhere]",role:"alert",children:ye}),ht&&v.jsx("p",{className:"inspector-error rounded-[7px] border border-danger p-2.5 text-[10px] text-danger [overflow-wrap:anywhere]",role:"alert",children:ht}),rt?v.jsxs("p",{className:"inspector-loading text-[11px] text-muted italic",role:"status",children:["Loading retained ",ke==="inputs"?"inputs":"output","…"]}):J&&ae in J?v.jsx(Ba,{value:J[ae]}):v.jsxs("p",{className:"empty-copy text-[11px] text-muted",children:["No retained ",ke," ",ke==="output"?"is":"are"," available."]}),Ie.nextPageToken&&v.jsx("button",{type:"button",className:"descriptor-page-action cursor-pointer rounded-md border border-line bg-panel px-2 py-[5px] font-mono text-[8px] text-acid disabled:cursor-wait disabled:text-muted",disabled:j,"aria-busy":j,onClick:tn,children:j?"Loading events…":"Load more events"})]}),ke==="trace"&&v.jsxs("section",{className:"inspector-panel inspector-trace-panel mb-0! flex h-full min-h-full min-w-0 flex-col gap-3",children:[v.jsxs("div",{className:"trace-toolbar flex items-center justify-between gap-2 [&_h3]:mt-0 [&_h3]:mb-[3px] [&_span]:font-mono [&_span]:text-[8px] [&_span]:text-muted",children:[v.jsxs("div",{children:[v.jsx("h3",{children:"RunTrace"}),v.jsxs("span",{children:[Et.length," retained ",Et.length===1?"turn":"turns"]})]}),v.jsx("button",{type:"button",className:`toggle flex-none cursor-pointer rounded-full border bg-panel px-2 py-[5px] font-mono text-[8px] ${X?"active border-acid text-acid":"border-line text-secondary"}`,onClick:()=>D(Q=>!Q),children:X?"Following live":"Follow latest"})]}),ye&&v.jsx("p",{className:"inspector-error rounded-[7px] border border-danger p-2.5 text-[10px] text-danger [overflow-wrap:anywhere]",role:"alert",children:ye}),j&&!Ot.length&&v.jsx("p",{className:"inspector-loading text-[11px] text-muted italic",role:"status",children:"Loading retained trace…"}),v.jsxs("div",{className:"inspector-trace-explorer min-h-48 min-w-0 flex-[1_1_auto] overflow-auto rounded-[7px] border border-line bg-panel p-2",ref:K,onScroll:Q=>{const se=Q.currentTarget,oe=se.scrollHeight-se.scrollTop-se.clientHeight;oe>wo&&D(!1),oe<=wo&&Ie.nextPageToken&&tn()},children:[v.jsx(Ba,{value:ie,onExpand:Q=>{if(Q===vn.values){Ie.nextPageToken&&tn();return}if(typeof Q!="object"||Q===null)return;const se=vn.descriptors.get(Q);se&&vl(se)}}),j&&Ot.length>0&&v.jsx("p",{className:"inspector-loading text-[11px] text-muted italic",role:"status",children:"Loading more retained trace…"}),!j&&!Ie.nextPageToken&&Ot.length>0&&v.jsx("p",{className:"inspector-end-state mt-2 text-center font-mono text-[8px] text-muted uppercase",children:"End of retained trace"})]}),Ie.nextPageToken&&v.jsx("button",{type:"button",className:"descriptor-page-action cursor-pointer rounded-md border border-line bg-panel px-2 py-[5px] font-mono text-[8px] text-acid disabled:cursor-wait disabled:text-muted",disabled:j,"aria-busy":j,onClick:tn,children:j?"Loading events…":"Load more trace"})]})]})]})}function mT(a,n,i){const o=new Array(a);return new Proxy(o,{get(u,s,d){if(typeof s=="string"){const h=s.charCodeAt(0);if(h>=48&&h<=57){const m=+s;if(Number.isInteger(m)&&m>=0&&mo[g]!==p))&&(o=h,u=n(...h),i?.onChange&&!(s&&i.skipInitialOnChange)&&i.onChange(u),s=!1),u}return d.updateDeps=h=>{o=h},d}function Wm(a,n){if(a===void 0)throw new Error("Unexpected undefined");return a}const gT=(a,n)=>Math.abs(a-n)<1.01,yT=(a,n,i)=>{let o;return function(...u){a.clearTimeout(o),o=a.setTimeout(()=>n.apply(this,u),i)}};let Ua;const Ac=()=>{if(Ua!==void 0)return Ua;if(typeof navigator>"u")return Ua=!1;if(/iP(hone|od|ad)/.test(navigator.userAgent))return Ua=!0;const a=navigator.maxTouchPoints;return Ua=navigator.platform==="MacIntel"&&a!==void 0&&a>0},Pm=a=>{const{offsetWidth:n,offsetHeight:i}=a;return{width:n,height:i}},bT=a=>a,xT=a=>{const n=Math.max(a.startIndex-a.overscan,0),o=Math.min(a.endIndex+a.overscan,a.count-1)-n+1,u=new Array(o);for(let s=0;s{const i=a.scrollElement;if(!i)return;const o=a.targetWindow;if(!o)return;const u=d=>{const{width:h,height:m}=d;n({width:Math.round(h),height:Math.round(m)})};if(u(Pm(i)),!o.ResizeObserver)return()=>{};const s=new o.ResizeObserver(d=>{const h=()=>{const m=d[0];if(m?.borderBoxSize){const p=m.borderBoxSize[0];if(p){u({width:p.inlineSize,height:p.blockSize});return}}u(Pm(i))};a.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(h):h()});return s.observe(i,{box:"border-box"}),()=>{s.unobserve(i)}},_o={passive:!0},ST=typeof window>"u"?!0:"onscrollend"in window,kT=(a,n,i)=>{const o=a.scrollElement;if(!o)return;const u=a.targetWindow;if(!u)return;const s=a.options.useScrollendEvent&&ST;let d=0;const h=s?null:yT(u,()=>n(d,!1),a.options.isScrollingResetDelay),m=b=>()=>{d=i(o),h?.(),n(d,b)},p=m(!0),g=m(!1);return o.addEventListener("scroll",p,_o),s&&o.addEventListener("scrollend",g,_o),()=>{o.removeEventListener("scroll",p),s&&o.removeEventListener("scrollend",g)}},wT=(a,n)=>kT(a,n,i=>{const{horizontal:o,isRtl:u}=a.options;return o?i.scrollLeft*(u&&-1||1):i.scrollTop}),TT=(a,n,i)=>{if(i.options.useCachedMeasurements){const o=i.indexFromElement(a),u=i.options.getItemKey(o);return i.itemSizeCache.get(u)??i.options.estimateSize(o)}if(n?.borderBoxSize){const o=n.borderBoxSize[0];if(o)return Math.round(o[i.options.horizontal?"inlineSize":"blockSize"])}if(!n){const o=i.indexFromElement(a),u=i.options.getItemKey(o),s=i.itemSizeCache.get(u);if(s!==void 0)return s}return a[i.options.horizontal?"offsetWidth":"offsetHeight"]},ET=(a,{adjustments:n=0,behavior:i},o)=>{var u,s;(s=(u=o.scrollElement)==null?void 0:u.scrollTo)==null||s.call(u,{[o.options.horizontal?"left":"top"]:a+n,behavior:i})},_T=ET;class AT{constructor(n){this.unsubs=[],this.scrollElement=null,this.targetWindow=null,this.isScrolling=!1,this.scrollState=null,this.measurementsCache=[],this._flatMeasurements=null,this.itemSizeCache=new Map,this.itemSizeCacheVersion=0,this.laneAssignments=new Map,this.pendingMin=null,this.prevLanes=void 0,this.lanesChangedFlag=!1,this.lanesSettling=!1,this.pendingScrollAnchor=null,this.scrollRect=null,this.scrollOffset=null,this.scrollDirection=null,this.scrollAdjustments=0,this._iosDeferredAdjustment=0,this._iosTouching=!1,this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._intendedScrollOffset=null,this.elementsCache=new Map,this.now=()=>{var i,o,u;return((u=(o=(i=this.targetWindow)==null?void 0:i.performance)==null?void 0:o.now)==null?void 0:u.call(o))??Date.now()},this.observer=(()=>{let i=null;const o=()=>i||(!this.targetWindow||!this.targetWindow.ResizeObserver?null:i=new this.targetWindow.ResizeObserver(u=>{u.forEach(s=>{const d=()=>{const h=s.target,m=this.indexFromElement(h);if(!h.isConnected){this.observer.unobserve(h);for(const[p,g]of this.elementsCache)if(g===h){this.elementsCache.delete(p);break}return}this.shouldMeasureDuringScroll(m)&&this.resizeItem(m,this.options.measureElement(h,s,this))};this.options.useAnimationFrameWithResizeObserver?requestAnimationFrame(d):d()})}));return{disconnect:()=>{var u;(u=o())==null||u.disconnect(),i=null},observe:u=>{var s;return(s=o())==null?void 0:s.observe(u,{box:"border-box"})},unobserve:u=>{var s;return(s=o())==null?void 0:s.unobserve(u)}}})(),this.range=null,this.setOptions=i=>{var o,u;const s={debug:!1,initialOffset:0,overscan:1,paddingStart:0,paddingEnd:0,scrollPaddingStart:0,scrollPaddingEnd:0,horizontal:!1,getItemKey:bT,rangeExtractor:xT,onChange:()=>{},measureElement:TT,initialRect:{width:0,height:0},scrollMargin:0,gap:0,indexAttribute:"data-index",initialMeasurementsCache:[],lanes:1,anchorTo:"start",followOnAppend:!1,scrollEndThreshold:1,isScrollingResetDelay:150,enabled:!0,isRtl:!1,useScrollendEvent:!1,useAnimationFrameWithResizeObserver:!1,laneAssignmentMode:"estimate",useCachedMeasurements:!1};for(const k in i){const S=i[k];S!==void 0&&(s[k]=S)}const d=this.options;let h=null,m=null,p=!1;if(d!==void 0&&d.enabled&&s.enabled&&s.anchorTo==="end"&&this.scrollElement!==null){const k=d.count,S=s.count,j=this.getMeasurements(),I=k>0?((o=j[0])==null?void 0:o.key)??d.getItemKey(0):null,X=k>0?((u=j[k-1])==null?void 0:u.key)??d.getItemKey(k-1):null;if(S!==k||k>0&&S>0&&(s.getItemKey(0)!==I||s.getItemKey(S-1)!==X)){p=!0;const B=k>0?this.getVirtualItemForOffset(this.getScrollOffset())??j[0]:null;B&&(h=[B.key,this.getScrollOffset()-B.start]);const F=s.followOnAppend===!0?"auto":s.followOnAppend||null;F&&S>k&&this.isAtEnd(d.scrollEndThreshold)&&(k===0||s.getItemKey(S-1)!==X)&&(m=F)}}this.options=s,p&&(this.pendingMin=0,this.itemSizeCacheVersion++);let g=!1,b=0;if(h&&this.scrollOffset!==null){const[k,S]=h,j=this.getMeasurements(),{count:I,getItemKey:X}=this.options;let D=0;for(;D{var o,u;(u=(o=this.options).onChange)==null||u.call(o,this,i)},this.maybeNotify=Ni(()=>(this.calculateRange(),[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]),i=>{this.notify(i)},{key:!1,debug:()=>this.options.debug,initialDeps:[this.isScrolling,this.range?this.range.startIndex:null,this.range?this.range.endIndex:null]}),this.cleanup=()=>{this.unsubs.filter(Boolean).forEach(i=>i()),this.unsubs=[],this.observer.disconnect(),this.rafId!=null&&this.targetWindow&&(this.targetWindow.cancelAnimationFrame(this.rafId),this.rafId=null),this.scrollState=null,this._iosDeferredAdjustment=0,this._iosTouching=!1,this._iosJustTouchEnded=!1,this.scrollElement=null,this.targetWindow=null},this._didMount=()=>()=>{this.cleanup()},this._willUpdate=()=>{var i;const o=this.options.enabled?this.options.getScrollElement():null;if(this.scrollElement!==o){if(this.cleanup(),!o){this.maybeNotify();return}if(this.scrollElement=o,this.scrollElement&&"ownerDocument"in this.scrollElement?this.targetWindow=this.scrollElement.ownerDocument.defaultView:this.targetWindow=((i=this.scrollElement)==null?void 0:i.window)??null,this.elementsCache.forEach(s=>{this.observer.observe(s)}),this.unsubs.push(this.options.observeElementRect(this,s=>{this.scrollRect=s,this.maybeNotify()})),this.unsubs.push(this.options.observeElementOffset(this,(s,d)=>{if(d&&this._intendedScrollOffset===null&&s===this.scrollOffset)return;this._intendedScrollOffset!==null&&Math.abs(s-this._intendedScrollOffset)<1.5&&(s=this._intendedScrollOffset),this._intendedScrollOffset=null,this.scrollAdjustments=0;const h=this.getScrollOffset();this.scrollDirection=d?h===s?this.scrollDirection:h{this._iosTouching=!0,this._iosJustTouchEnded=!1,this._iosTouchEndTimerId!==null&&this.targetWindow!=null&&(this.targetWindow.clearTimeout(this._iosTouchEndTimerId),this._iosTouchEndTimerId=null)},h=()=>{this._iosTouching=!1,!(!Ac()||this.targetWindow==null)&&(this._iosJustTouchEnded=!0,this._iosTouchEndTimerId=this.targetWindow.setTimeout(()=>{this._iosJustTouchEnded=!1,this._iosTouchEndTimerId=null,this._flushIosDeferredIfReady()},150))};s.addEventListener("touchstart",d,_o),s.addEventListener("touchend",h,_o),this.unsubs.push(()=>{s.removeEventListener("touchstart",d),s.removeEventListener("touchend",h),this._iosTouchEndTimerId!==null&&this.targetWindow!=null&&(this.targetWindow.clearTimeout(this._iosTouchEndTimerId),this._iosTouchEndTimerId=null)})}this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})}const u=this.pendingScrollAnchor;if(this.pendingScrollAnchor=null,u&&this.scrollElement&&this.options.enabled){const[s,d,h,m]=u;s!==null&&!h&&(Ac()&&(this.isScrolling||this._iosTouching||this._iosJustTouchEnded)?m!==0&&(this._iosDeferredAdjustment+=m):this._scrollToOffset(this.getScrollOffset(),{adjustments:void 0,behavior:void 0})),h&&this.scrollToEnd({behavior:h})}},this._flushIosDeferredIfReady=()=>{if(this._iosDeferredAdjustment===0||this.isScrolling||this._iosTouching||this._iosJustTouchEnded)return;const i=this.getScrollOffset(),o=this.getMaxScrollOffset();if(i<0||i>o)return;if(this._iosDeferredAdjustment<0&&i>=o-1){this._iosDeferredAdjustment=0;return}const u=this._iosDeferredAdjustment;this._iosDeferredAdjustment=0,this._scrollToOffset(i,{adjustments:this.scrollAdjustments+=u,behavior:void 0})},this.rafId=null,this.getSize=()=>this.options.enabled?(this.scrollRect=this.scrollRect??this.options.initialRect,this.scrollRect[this.options.horizontal?"width":"height"]):(this.scrollRect=null,0),this.getScrollOffset=()=>this.options.enabled?(this.scrollOffset=this.scrollOffset??(typeof this.options.initialOffset=="function"?this.options.initialOffset():this.options.initialOffset),this.scrollOffset):(this.scrollOffset=null,0),this.getMeasurementOptions=Ni(()=>[this.options.count,this.options.paddingStart,this.options.scrollMargin,this.options.getItemKey,this.options.enabled,this.options.lanes,this.options.laneAssignmentMode,this.options.gap],(i,o,u,s,d,h,m,p)=>(this.prevLanes!==void 0&&this.prevLanes!==h&&(this.lanesChangedFlag=!0),this.prevLanes=h,this.pendingMin=null,{count:i,paddingStart:o,scrollMargin:u,getItemKey:s,enabled:d,lanes:h,laneAssignmentMode:m,gap:p}),{key:!1}),this.getMeasurements=Ni(()=>[this.getMeasurementOptions(),this.itemSizeCacheVersion],({count:i,paddingStart:o,scrollMargin:u,getItemKey:s,enabled:d,lanes:h,laneAssignmentMode:m,gap:p},g)=>{const b=this.itemSizeCache;if(!d)return this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),[];if(this.laneAssignments.size>i)for(const D of this.laneAssignments.keys())D>=i&&this.laneAssignments.delete(D);this.lanesChangedFlag&&(this.lanesChangedFlag=!1,this.lanesSettling=!0,this.measurementsCache=[],this.itemSizeCache.clear(),this.laneAssignments.clear(),this.pendingMin=null),this.measurementsCache.length===0&&!this.lanesSettling&&(this.measurementsCache=this.options.initialMeasurementsCache,this.measurementsCache.forEach(D=>{this.itemSizeCache.set(D.key,D.size)}));const k=this.lanesSettling?0:this.pendingMin??0;if(this.pendingMin=null,this.lanesSettling&&this.measurementsCache.length===i&&(this.lanesSettling=!1),h===1){const D=i*2;let G=this._flatMeasurements;if(!G||G.length0&&te.set(G.subarray(0,k*2)),G=te,this._flatMeasurements=G}let B;if(k===0)B=o+u;else{const te=k-1;B=G[te*2]+G[te*2+1]+p}for(let te=k;te1){F=B;const pe=j[F],le=pe!==void 0?S[pe]:void 0;te=le?le.end+p:o+u}else if(X===h){let pe=0,le=I[0],Z=j[0];for(let me=1;methis.options.debug}),this.calculateRange=Ni(()=>[this.getMeasurements(),this.getSize(),this.getScrollOffset(),this.options.lanes],(i,o,u,s)=>i.length===0||o===0?(this.range=null,null):(this.range=zT(i,o,u,s,s===1&&this._flatMeasurements!=null?this._flatMeasurements:null),this.range),{key:!1,debug:()=>this.options.debug}),this.getVirtualIndexes=Ni(()=>{let i=null,o=null;const u=this.calculateRange();return u&&(i=u.startIndex,o=u.endIndex),this.maybeNotify.updateDeps([this.isScrolling,i,o]),[this.options.rangeExtractor,this.options.overscan,this.options.count,i,o]},(i,o,u,s,d)=>s===null||d===null?[]:i({startIndex:s,endIndex:d,overscan:o,count:u}),{key:!1,debug:()=>this.options.debug}),this.indexFromElement=i=>{const o=this.options.indexAttribute,u=i.getAttribute(o);return u?parseInt(u,10):(console.warn(`Missing attribute name '${o}={index}' on measured element.`),-1)},this.shouldMeasureDuringScroll=i=>{var o;if(!this.scrollState||this.scrollState.behavior!=="smooth")return!0;const u=this.scrollState.index??((o=this.getVirtualItemForOffset(this.scrollState.lastTargetOffset))==null?void 0:o.index);if(u!==void 0&&this.range){const s=Math.max(this.options.overscan,Math.ceil((this.range.endIndex-this.range.startIndex)/2)),d=Math.max(0,u-s),h=Math.min(this.options.count-1,u+s);return i>=d&&i<=h}return!0},this.measureElement=i=>{if(!i){this.elementsCache.forEach((d,h)=>{d.isConnected||(this.observer.unobserve(d),this.elementsCache.delete(h))});return}const o=this.indexFromElement(i),u=this.options.getItemKey(o),s=this.elementsCache.get(u);s!==i&&(s&&this.observer.unobserve(s),this.observer.observe(i),this.elementsCache.set(u,i)),(!this.isScrolling||this.scrollState)&&this.shouldMeasureDuringScroll(o)&&this.resizeItem(o,this.options.measureElement(i,void 0,this))},this.resizeItem=(i,o)=>{var u,s;if(i<0||i>=this.options.count)return;let d,h,m;const p=this._flatMeasurements;if(this.options.lanes===1&&p!==null)m=this.options.getItemKey(i),h=p[i*2],d=p[i*2+1];else{const k=this.measurementsCache[i];if(!k)return;m=k.key,h=k.start,d=k.size}const g=this.itemSizeCache.get(m)??d,b=o-g;if(b!==0){const k=this.options.anchorTo==="end"&&((u=this.scrollState)==null?void 0:u.behavior)!=="smooth"&&this.getVirtualDistanceFromEnd()<=this.options.scrollEndThreshold,S=k?this.getTotalSize():0,j=this.getScrollOffset()+this.scrollAdjustments,X=!this.itemSizeCache.has(m)?h[this.getVirtualIndexes(),this.getMeasurements()],(i,o)=>{const u=[];for(let s=0,d=i.length;sthis.options.debug}),this.getVirtualItemForOffset=i=>{const o=this.getMeasurements();if(o.length===0)return;const u=this._flatMeasurements,s=this.options.lanes===1&&u!=null,d=uy(0,o.length-1,s?h=>u[h*2]:h=>Wm(o[h]).start,i);return Wm(o[d])},this.getMaxScrollOffset=()=>{if(!this.scrollElement)return 0;if("scrollHeight"in this.scrollElement)return this.options.horizontal?this.scrollElement.scrollWidth-this.scrollElement.clientWidth:this.scrollElement.scrollHeight-this.scrollElement.clientHeight;{const i=this.scrollElement.document.documentElement;return this.options.horizontal?i.scrollWidth-this.scrollElement.innerWidth:i.scrollHeight-this.scrollElement.innerHeight}},this.getVirtualDistanceFromEnd=()=>Math.max(this.getTotalSize()-this.getSize()-this.getScrollOffset(),0),this.getDistanceFromEnd=()=>Math.max(this.getMaxScrollOffset()-this.getScrollOffset(),0),this.isAtEnd=(i=this.options.scrollEndThreshold)=>this.getDistanceFromEnd()<=i,this.getOffsetForAlignment=(i,o,u=0)=>{if(!this.scrollElement)return 0;const s=this.getSize(),d=this.getScrollOffset();o==="auto"&&(o=i>=d+s?"end":"start"),o==="center"?i+=(u-s)/2:o==="end"&&(i-=s);const h=this.getMaxScrollOffset();return Math.max(Math.min(h,i),0)},this.getOffsetForIndex=(i,o="auto")=>{i=Math.max(0,Math.min(i,this.options.count-1));const u=this.getSize(),s=this.getScrollOffset(),d=this.measurementsCache[i];if(!d)return;if(o==="auto")if(d.end>=s+u-this.options.scrollPaddingEnd)o="end";else if(d.start<=s+this.options.scrollPaddingStart)o="start";else return[s,o];if(o==="end"&&i===this.options.count-1)return[this.getMaxScrollOffset(),o];const h=o==="end"?d.end+this.options.scrollPaddingEnd:d.start-this.options.scrollPaddingStart;return[this.getOffsetForAlignment(h,o,d.size),o]},this.scrollToOffset=(i,{align:o="start",behavior:u="auto"}={})=>{this._iosDeferredAdjustment=0;const s=this.getOffsetForAlignment(i,o),d=this.now();this.scrollState={index:null,align:o,behavior:u,startedAt:d,lastTargetOffset:s,stableFrames:0},this._scrollToOffset(s,{adjustments:void 0,behavior:u}),this.scheduleScrollReconcile()},this.scrollToIndex=(i,{align:o="auto",behavior:u="auto"}={})=>{this._iosDeferredAdjustment=0,i=Math.max(0,Math.min(i,this.options.count-1));const s=this.getOffsetForIndex(i,o);if(!s)return;const[d,h]=s,m=this.now();this.scrollState={index:i,align:h,behavior:u,startedAt:m,lastTargetOffset:d,stableFrames:0},this._scrollToOffset(d,{adjustments:void 0,behavior:u}),this.scheduleScrollReconcile()},this.scrollBy=(i,{behavior:o="auto"}={})=>{const u=this.getScrollOffset()+i,s=this.now();this.scrollState={index:null,align:"start",behavior:o,startedAt:s,lastTargetOffset:u,stableFrames:0},this._scrollToOffset(u,{adjustments:void 0,behavior:o}),this.scheduleScrollReconcile()},this.scrollToEnd=({behavior:i="auto"}={})=>{if(this.options.count>0){this.scrollToIndex(this.options.count-1,{align:"end",behavior:i});return}this.scrollToOffset(Math.max(this.getTotalSize()-this.getSize(),0),{behavior:i})},this.getTotalSize=()=>{var i;const o=this.getMeasurements();let u;if(o.length===0)u=this.options.paddingStart;else if(this.options.lanes===1){const s=o.length-1,d=this._flatMeasurements;d!=null?u=d[s*2]+d[s*2+1]:u=((i=o[s])==null?void 0:i.end)??0}else{const s=Array(this.options.lanes).fill(null);let d=o.length-1;for(;d>=0&&s.some(h=>h===null);){const h=o[d];s[h.lane]===null&&(s[h.lane]=h.end),d--}u=Math.max(...s.filter(h=>h!==null))}return Math.max(u-this.options.scrollMargin+this.options.paddingEnd,0)},this.takeSnapshot=()=>{const i=[];if(this.itemSizeCache.size===0)return i;const o=this.getMeasurements();for(const u of o)u&&this.itemSizeCache.has(u.key)&&i.push({index:u.index,key:u.key,start:u.start,size:u.size,end:u.end,lane:u.lane});return i},this._scrollToOffset=(i,{adjustments:o,behavior:u})=>{this._intendedScrollOffset=i+(o??0),this.options.scrollToFn(i,{behavior:u,adjustments:o},this)},this.measure=()=>{this.pendingMin=null,this.itemSizeCache.clear(),this.laneAssignments.clear(),this.itemSizeCacheVersion++,this.notify(!1)},this.setOptions(n)}applyScrollAdjustment(n,i){return n===0?!1:Ac()&&(this.isScrolling||this._iosTouching||this._iosJustTouchEnded)?(this._iosDeferredAdjustment+=n,!1):(this._scrollToOffset(this.getScrollOffset(),{adjustments:this.scrollAdjustments+=n,behavior:i}),this.scrollOffset!==null&&(this.scrollOffset+=this.scrollAdjustments,this.scrollOffset<0&&(this.scrollOffset=0),this.scrollAdjustments=0),!0)}scheduleScrollReconcile(){if(!this.targetWindow){this.scrollState=null;return}this.rafId==null&&(this.rafId=this.targetWindow.requestAnimationFrame(()=>{this.rafId=null,this.reconcileScroll()}))}reconcileScroll(){if(!this.scrollState||!this.scrollElement)return;if(this.now()-this.scrollState.startedAt>5e3){this.scrollState=null;return}const o=this.scrollState.index!=null?this.getOffsetForIndex(this.scrollState.index,this.scrollState.align):void 0,u=o?o[0]:this.scrollState.lastTargetOffset,s=1,d=u!==this.scrollState.lastTargetOffset;if(!d&&gT(u,this.getScrollOffset())){if(this.scrollState.stableFrames++,this.scrollState.stableFrames>=s){this.getScrollOffset()!==u&&this._scrollToOffset(u,{adjustments:void 0,behavior:"auto"}),this.scrollState=null;return}}else if(this.scrollState.stableFrames=0,d){const h=this.getSize()||600,m=Math.abs(u-this.getScrollOffset()),p=this.scrollState.behavior==="smooth"&&m>h;this.scrollState.lastTargetOffset=u,p||(this.scrollState.behavior="auto"),this._scrollToOffset(u,{adjustments:void 0,behavior:p?"smooth":"auto"})}this.scheduleScrollReconcile()}}const uy=(a,n,i,o)=>{for(;a<=n;){const u=(a+n)/2|0,s=i(u);if(so)n=u-1;else return u}return a>0?a-1:0};function NT(a,n,i){let o=0;for(;o<=n;){const u=(o+n)/2|0,s=a[u*2];if(si)n=u-1;else return u}return o>0?o-1:0}function zT(a,n,i,o,u){const s=a.length-1;if(a.length<=o)return{startIndex:0,endIndex:s};if(o===1&&u!==null){const p=NT(u,s,i);let g=p;const b=i+n;for(;ga[p].start,i),m=h;if(o===1)for(;m1){const p=Array(o).fill(0);for(;mb=0&&g.some(b=>b>=i);){const b=a[h];g[b.lane]=b.start,h--}h=Math.max(0,h-h%o),m=Math.min(s,m+(o-1-m%o))}return{startIndex:h,endIndex:m}}const Nc=typeof document<"u"?L.useLayoutEffect:L.useEffect;function RT({useFlushSync:a=!0,directDomUpdates:n=!1,directDomUpdatesMode:i="transform",...o}){const u=L.useReducer(g=>g+1,0)[1],s=L.useRef({enabled:n,mode:i,container:null,lastSize:null,lastPositions:new WeakMap,prevRange:null});s.current.enabled=n,s.current.mode=i;const d=g=>{const b=s.current;if(!b.enabled||!b.container)return;const k=g.getTotalSize();if(k!==b.lastSize){b.lastSize=k;const S=g.options.horizontal?"width":"height";b.container.style[S]=`${k}px`}},h=g=>{const b=s.current;if(!b.enabled||!b.container)return;d(g);const k=!!g.options.horizontal,S=b.mode==="transform",j=k?"left":"top",I=g.options.scrollMargin,X=g.getVirtualItems();for(const D of X){const G=D.start-I,B=g.elementsCache.get(D.key);B&&b.lastPositions.get(B)!==G&&(b.lastPositions.set(B,G),S?B.style.transform=k?`translate3d(${G}px, 0, 0)`:`translate3d(0, ${G}px, 0)`:B.style[j]=`${G}px`)}},m={...o,onChange:(g,b)=>{var k;const S=s.current;let j=!0;if(S.enabled){h(g);const I=g.range,X=S.prevRange;j=!X||X.isScrolling!==g.isScrolling||X.startIndex!==I?.startIndex||X.endIndex!==I?.endIndex,j&&(S.prevRange=I?{startIndex:I.startIndex,endIndex:I.endIndex,isScrolling:g.isScrolling}:null)}j&&(a&&b?q0.flushSync(u):u()),(k=o.onChange)==null||k.call(o,g,b)}},[p]=L.useState(()=>{const g=new AT(m);return Object.assign(g,{containerRef:b=>{const k=s.current;if(k.container=b,k.lastSize=null,b&&k.enabled){const S=g.getTotalSize();k.lastSize=S;const j=g.options.horizontal?"width":"height";b.style[j]=`${S}px`}}})});return p.setOptions(m),Nc(()=>p._didMount(),[]),Nc(()=>(d(p),p._willUpdate())),Nc(()=>{h(p)}),p}function cy(a){return RT({observeElementRect:vT,observeElementOffset:wT,scrollToFn:_T,...a})}const OT=/\u001B\[([0-9;]*)m/g,zi=["#1f2937","#c43d36","#16805d","#a15c00","#2563eb","#a855f7","#0f766e","#dfe4e1","#64748b","#ef4444","#22c55e","#f59e0b","#3b82f6","#c084fc","#14b8a6","#ffffff"];function fy(){return{foreground:void 0,background:void 0,bold:!1,dim:!1,italic:!1,underline:!1,inverse:!1,strikethrough:!1}}function go(a){return a!==void 0&&a>=0&&a<=255}function Vc(a,n,i){return`rgb(${a}, ${n}, ${i})`}function CT(a){if(a{const i=Number(n);return Number.isInteger(i)&&i>=0?[i]:[]}):[0]}function MT(a,n){const i={...a};for(let o=0;o=30&&u<=37)i.foreground=zi[u-30];else if(u>=40&&u<=47)i.background=zi[u-40];else if(u>=90&&u<=97)i.foreground=zi[u-90+8];else if(u>=100&&u<=107)i.background=zi[u-100+8];else if(u===38||u===48){const s=u===38?"foreground":"background",d=n[o+1];d===5&&go(n[o+2])?(i[s]=CT(n[o+2]),o+=2):d===2&&go(n[o+2])&&go(n[o+3])&&go(n[o+4])&&(i[s]=Vc(n[o+2],n[o+3],n[o+4]),o+=4)}}return i}function jT(a){const n=[];let i=fy(),o=0;for(const u of a.matchAll(OT))u.index>o&&n.push({text:a.slice(o,u.index),state:i}),i=MT(i,DT(u[1])),o=u.index+u[0].length;return o{const o=LT(n.state);return o?v.jsx("span",{style:o,children:n.text},i):n.text})}const UT=20,IT=48,qT=12,Ao=140,HT=260,VT=720,eg=16,dy=[],zc={records:dy,nextPageToken:"",nextCursor:"0"};function yo(a){const n=a?.parentElement?.clientHeight??0,i=n>0?n:window.innerHeight;return Math.max(Ao,Math.floor(i*.75))}function bo(a,n){return Math.min(n,Math.max(Ao,a))}function GT(a){return Number.isFinite(a)?new Date(a*1e3).toISOString().slice(11,23):"--:--:--.---"}function YT({api:a,run:n,nodeId:i,liveLogs:o=dy,onSelectNode:u}){const[s,d]=L.useState(!0),[h,m]=L.useState(!0),[p,g]=L.useState(HT),[b,k]=L.useState(VT),[S,j]=L.useState(zc),[I,X]=L.useState(),[D,G]=L.useState(!1),[B,F]=L.useState(),[te,q]=L.useState(()=>new Map),[re,ue]=L.useState(!1),[de,pe]=L.useState(),[le,Z]=L.useState(0),me=L.useRef(null),ne=L.useRef(0),$=L.useRef(!1),R=L.useRef(null),K=L.useRef(0),fe=L.useRef(!1),W=L.useRef(new Set),w=L.useRef(new Set),ze=L.useRef([]),Se=L.useRef(null),T=L.useRef(void 0),Re=L.useRef(null),Ye=L.useRef(void 0),Le=n.summary?.runId??"",ke=n.operatorInstanceId,Ke=n.asOfSequence,We=n.logPageToken,Ie=i??"",Pe=`${ke}\0${Le}\0${Ke}\0${We}\0${Ie}`,St=I===Pe?S:zc,Tt=L.useCallback(()=>{K.current+=1,R.current?.abort(),R.current=null,fe.current=!1,W.current.clear()},[]);L.useEffect(()=>()=>{me.current?.abort(),Tt()},[Tt]),L.useLayoutEffect(()=>{const ie=()=>{const ce=yo(Re.current);k(ce),g(z=>bo(z,ce))};return ie(),window.addEventListener("resize",ie),()=>window.removeEventListener("resize",ie)},[]),L.useEffect(()=>{me.current?.abort(),$.current=!1,Tt();const ie=++ne.current;if(j(zc),X(void 0),G(!1),F(void 0),q(new Map),ue(!1),pe(void 0),w.current.clear(),T.current=void 0,m(!0),!s)return;const ce=new AbortController;return me.current=ce,We?($.current=!0,G(!0),a.listLogPage({pageToken:We,afterSequence:"0",beforeSequence:"0",pageSize:ko,nodeId:Ie,order:Mt.NEWEST_FIRST,expectedOperatorInstanceId:ke,expectedAsOfSequence:Ke},ce.signal).then(z=>{ce.signal.aborted||ne.current!==ie||(j(z),X(Pe))}).catch(z=>{ce.signal.aborted||ne.current!==ie||F(z instanceof Error?z.message:"Logs unavailable")}).finally(()=>{ce.signal.aborted||ne.current!==ie||($.current=!1,G(!1))}),()=>{ce.abort(),me.current===ce&&($.current=!1)}):(X(Pe),()=>ce.abort())},[Tt,a,Ke,Pe,Ie,s,ke,We]);const nt=L.useMemo(()=>{const ie=new Map,ce=new Set;for(const z of St.records)(!Ie||z.nodeId===Ie)&&ie.set(z.sequence,z);for(const z of o)(!Ie||z.nodeId===Ie)&&(ie.set(z.sequence,z),ce.add(z.sequence));return Gc(ie,z=>z.sequence,"older",ce).sort((z,J)=>Oc(z.sequence,J.sequence))},[St.records,Ie,o]);ze.current=nt;const jt=L.useCallback(()=>{if(!St.nextPageToken||$.current)return;me.current?.abort();const ie=++ne.current,ce=new AbortController;me.current=ce,$.current=!0,F(void 0),G(!0),m(!1);const z=Se.current;T.current=z?{height:z.scrollHeight,top:z.scrollTop}:void 0,a.listLogPage({pageToken:St.nextPageToken,afterSequence:"0",beforeSequence:St.nextCursor,pageSize:ko,nodeId:Ie,order:Mt.NEWEST_FIRST,expectedOperatorInstanceId:ke,expectedAsOfSequence:Ke},ce.signal).then(J=>{ce.signal.aborted||ne.current!==ie||j(ae=>yg(ae,J,ye=>ye.sequence,"older"))}).catch(J=>{T.current=void 0,!(ce.signal.aborted||ne.current!==ie)&&F(J instanceof Error?J.message:"Logs unavailable")}).finally(()=>{ce.signal.aborted||ne.current!==ie||($.current=!1,G(!1))})},[St.nextCursor,St.nextPageToken,a,Ke,Ie,ke]);L.useLayoutEffect(()=>{const ie=T.current,ce=Se.current;!ie||!ce||(ce.scrollTop=ie.top+ce.scrollHeight-ie.height,T.current=void 0)},[nt.length]),L.useEffect(()=>{if(!s||!nt.length||fe.current)return;const ie=nt.filter(ae=>!te.has(ae.bodyToken)&&!W.current.has(ae.bodyToken)&&!w.current.has(ae.bodyToken)).slice(0,UT);if(!ie.length)return;const ce=K.current,z=new AbortController;R.current=z,fe.current=!0;for(const ae of ie)W.current.add(ae.bodyToken);ue(!0);const J=ie.map(async ae=>{try{const ye=await a.readTextDetail(ae.bodyToken,z.signal);return{entry:ae,body:ye}}catch(ye){return{entry:ae,error:ye}}});Promise.all(J).then(ae=>{if(z.signal.aborted||K.current!==ce)return;const ye=ae.find(rt=>"error"in rt);ye&&"error"in ye&&pe(ye.error instanceof Error?ye.error.message:"Log text unavailable"),ae.some(rt=>"body"in rt&&typeof rt.body=="string"&&Ia(rt.body,rt.entry.sizeBytes)>ji)&&pe("A log record exceeds the browser detail limit."),q(rt=>{const ht=new Map(rt);for(const oe of ae){if(!("body"in oe)||typeof oe.body!="string"){w.current.add(oe.entry.bodyToken);continue}if(Ia(oe.body,oe.entry.sizeBytes)>ji){w.current.add(oe.entry.bodyToken);continue}ht.set(oe.entry.bodyToken,oe.body)}const Q=new Map(ze.current.map(oe=>[oe.bodyToken,oe]));for(const oe of ht.keys())Q.has(oe)||ht.delete(oe);for(const oe of w.current)Q.has(oe)||w.current.delete(oe);let se=0;for(const[oe,be]of ht)se+=Ia(be,Q.get(oe)?.sizeBytes);for(const oe of ze.current){if(se<=ji)break;const be=ht.get(oe.bodyToken);be!==void 0&&(ht.delete(oe.bodyToken),w.current.add(oe.bodyToken),se-=Ia(be,oe.sizeBytes))}return ht})}).finally(()=>{for(const ae of ie)W.current.delete(ae.bodyToken);R.current===z&&(R.current=null,fe.current=!1,!(z.signal.aborted||K.current!==ce)&&(ue(!1),Z(ae=>ae+1)))})},[a,nt,le,s,te]),L.useEffect(()=>{const ie=Se.current;!s||!h||!ie||(ie.scrollTop=ie.scrollHeight)},[nt.length,le,s,h]);const gn=L.useCallback(()=>{const ie=Se.current;ie&&(ie.scrollTop=ie.scrollHeight),m(!0)},[]),tn=ie=>{Ye.current&&(ie.currentTarget.hasPointerCapture?.(ie.pointerId)&&ie.currentTarget.releasePointerCapture(ie.pointerId),Ye.current=void 0)},Ot=ie=>{const ce=yo(Re.current);k(ce);let z;ie.key==="ArrowUp"&&(z=p+eg),ie.key==="ArrowDown"&&(z=p-eg),ie.key==="Home"&&(z=Ao),ie.key==="End"&&(z=ce),z!==void 0&&(ie.preventDefault(),g(bo(z,ce)))},Et=cy({count:nt.length,getScrollElement:()=>Se.current,estimateSize:()=>IT,getItemKey:ie=>nt[ie].sequence,overscan:qT}),st=n.topology?.displayNames??{},xt=L.useMemo(()=>{const ie=new Map,ce=new Map;for(const z of n.nodes)ie.set(z.nodeId,z),ce.has(z.name)?ce.set(z.name,void 0):ce.set(z.name,z);return{byId:ie,byUniqueName:ce}},[n.nodes]),vl=i?st[i]&&st[i]!==i?`${st[i]} · ${i}`:i:"All steps",vn=s?{flexBasis:`${p}px`}:void 0;return v.jsxs("section",{ref:Re,className:`run-log-pane relative z-[6] grid min-h-0 min-w-0 flex-[0_0_35px] grid-rows-[35px_minmax(0,1fr)] border-t border-line bg-[rgba(255,255,255,.98)] shadow-[0_-5px_18px_rgba(20,31,26,.08)] ${s?"expanded min-h-[140px] max-h-[75%]":""}`,style:vn,"aria-label":"Run logs",children:[s&&v.jsx("div",{className:"run-log-resizer absolute -top-1 right-0 left-0 z-[2] h-[9px] cursor-ns-resize touch-none select-none after:absolute after:top-[3px] after:right-0 after:left-0 after:h-0.5 after:bg-line after:content-[''] after:transition-colors after:duration-150 hover:after:bg-acid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-acid focus-visible:after:bg-acid",role:"separator","aria-label":"Resize logs","aria-controls":"run-log-content","aria-orientation":"horizontal","aria-valuemin":Ao,"aria-valuemax":b,"aria-valuenow":p,"aria-valuetext":`${p} pixels high`,tabIndex:0,onKeyDown:Ot,onPointerDown:ie=>{ie.preventDefault();const ce=yo(Re.current);k(ce),Ye.current={clientY:ie.clientY,height:bo(p,ce)},ie.currentTarget.setPointerCapture?.(ie.pointerId)},onPointerMove:ie=>{const ce=Ye.current;if(!ce)return;const z=yo(Re.current);k(z),g(bo(ce.height+ce.clientY-ie.clientY,z))},onPointerUp:tn,onPointerCancel:tn}),v.jsxs("header",{className:"flex min-w-0 items-center gap-2.5 border-b border-line px-2.5",children:[v.jsxs("button",{type:"button",className:"run-log-collapse flex min-w-0 cursor-pointer items-center gap-[7px] border-0 bg-transparent py-1 text-left text-ink focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-acid [&>span:first-child]:w-2.5 [&>span:first-child]:text-acid [&>strong]:text-[10px] [&>strong]:tracking-[.08em] [&>strong]:uppercase","aria-expanded":s,"aria-controls":"run-log-content",onClick:()=>d(ie=>!ie),children:[v.jsx("span",{"aria-hidden":"true",children:s?"▾":"▸"}),v.jsx("strong",{children:"Logs"}),v.jsx("span",{className:"run-log-scope truncate font-mono text-[9px] text-secondary",children:vl})]}),v.jsxs("span",{className:"run-log-count ml-auto whitespace-nowrap font-mono text-[8px] text-muted",children:[nt.length," ",nt.length===1?"record":"records"]}),s&&v.jsxs("button",{type:"button",className:`toggle run-log-autoscroll inline-flex flex-none cursor-pointer items-center gap-[5px] rounded-full border bg-panel px-2 py-[5px] font-mono text-[8px] focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-acid [&>span]:text-xs [&>span]:leading-none [&>span]:text-acid ${h?"active border-acid text-acid":"border-line text-secondary"}`,"aria-label":"Auto-scroll logs","aria-pressed":h,title:h?"Pause auto-scroll":"Jump to latest logs and resume auto-scroll",onClick:()=>{h?m(!1):gn()},children:[v.jsx("span",{"aria-hidden":"true",children:"↓"}),h?"Auto-scroll on":"Auto-scroll off"]})]}),s&&v.jsxs("div",{className:"run-log-content grid min-h-0 min-w-0 grid-rows-[auto_auto_auto_minmax(0,1fr)_auto]",id:"run-log-content",children:[B&&v.jsx("p",{className:"inspector-error mb-1.5 rounded-[7px] border border-danger px-2 py-1.5 text-[10px] text-danger [overflow-wrap:anywhere]",role:"alert",children:B}),de&&v.jsx("p",{className:"inspector-error mb-1.5 rounded-[7px] border border-danger px-2 py-1.5 text-[10px] text-danger [overflow-wrap:anywhere]",role:"alert",children:de}),St.nextPageToken&&v.jsx("button",{type:"button",className:"descriptor-page-action run-log-older-action mb-1.5 cursor-pointer justify-self-start rounded-md border border-line bg-panel px-2 py-[5px] font-mono text-[8px] text-acid disabled:cursor-wait disabled:text-muted",disabled:D,"aria-busy":D,onClick:jt,children:D?"Loading older logs…":"Load older logs"}),v.jsx("div",{className:"run-log-scroll min-h-0 min-w-0 overflow-auto [&>.empty-copy]:m-3 [&>.inspector-loading]:m-3",ref:Se,onScroll:ie=>{const ce=ie.currentTarget;ce.scrollHeight-ce.scrollTop-ce.clientHeight>wo&&m(!1),ce.scrollTop<=wo&&St.nextPageToken&&jt()},children:D&&!nt.length?v.jsx("p",{className:"inspector-loading text-[11px] text-muted italic",role:"status",children:"Loading retained logs…"}):nt.length?v.jsx("div",{className:"run-log-virtual relative w-full",style:{height:Et.getTotalSize()},children:Et.getVirtualItems().map(ie=>{const ce=nt[ie.index],z=te.get(ce.bodyToken),ae=(xt.byId.get(ce.nodeId)??xt.byUniqueName.get(ce.nodeId))?.nodeId,ye=ae&&st[ae]||ce.nodeId;return v.jsxs("article",{className:"run-log-row absolute top-0 left-0 grid min-h-9 w-full grid-cols-[78px_minmax(120px,180px)_52px_minmax(12rem,1fr)] items-start gap-2 border-b border-[#edf0ee] bg-[#fbfcfb] px-[9px] py-1.5 font-mono text-[9px]/[1.45] text-secondary [&>time]:whitespace-nowrap [&>time]:text-muted [&>pre]:m-0 [&>pre]:min-w-0 [&>pre]:whitespace-pre-wrap [&>pre]:text-[#27332d] [&>pre]:[overflow-wrap:anywhere]","data-index":ie.index,ref:Et.measureElement,style:{transform:`translateY(${ie.start}px)`},children:[v.jsx("time",{dateTime:new Date(ce.timestamp*1e3).toISOString(),children:GT(ce.timestamp)}),ae?v.jsxs("button",{type:"button",className:"run-log-node min-w-0 cursor-pointer border-0 bg-transparent p-0 text-left [font:inherit] text-acid focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-acid [&>strong]:block [&>strong]:truncate [&>code]:mt-0.5 [&>code]:block [&>code]:truncate [&>code]:text-[8px] [&>code]:text-muted",onClick:()=>u(ae),children:[v.jsx("strong",{children:ye}),ye!==ce.nodeId&&v.jsx("code",{children:ae})]}):v.jsx("span",{className:"run-log-node min-w-0 text-left [font:inherit] text-acid [&>strong]:block [&>strong]:truncate",children:v.jsx("strong",{children:ye})}),v.jsx("span",{className:`run-log-level font-bold uppercase ${ce.level==="error"||ce.level==="critical"?`level-${ce.level} text-danger`:ce.level==="warning"?"level-warning text-amber":"text-secondary"}`,children:ce.level}),v.jsx("pre",{children:v.jsx(BT,{text:z??(w.current.has(ce.bodyToken)?"[log body omitted]":"Loading…")})})]},ce.sequence)})}):v.jsx("p",{className:"empty-copy text-[11px] text-muted",children:i?"No retained logs are available for this node.":"No retained logs are available for this run."})}),re&&v.jsx("p",{className:"inspector-loading run-log-decoding mt-[5px] text-[11px] text-muted italic",role:"status",children:"Decoding log text…"})]})]})}function FT({value:a,onChange:n}){const i=L.useRef(null);return L.useEffect(()=>{if(!i.current)return;const o=new Oa({parent:i.current,state:G0.create({doc:a,extensions:[Y0(),F0.of([]),Oa.lineWrapping,Oa.contentAttributes.of({"aria-label":"Workflow input JSON"}),Oa.theme({"&":{backgroundColor:"#ffffff",color:"#17211c"},".cm-content":{caretColor:"#2563eb",minHeight:"110px"},".cm-gutters":{backgroundColor:"#f6f8f7",color:"#7b8680",border:"0"},"&.cm-focused":{outline:"1px solid #9bb6f5"}}),Oa.updateListener.of(u=>{u.docChanged&&n(u.state.doc.toString())})]})});return()=>o.destroy()},[]),v.jsx("div",{className:"json-editor overflow-hidden rounded-[7px] border border-line text-[10px]",ref:i})}function XT(a){const n=JSON.parse(a);if(!mn(n))throw new Error("Run input must be a JSON object");return n}function QT({workflow:a,run:n,pending:i,onStart:o,onCancel:u,onViewWorkflow:s}){const[d,h]=L.useState(!1),[m,p]=L.useState("{}"),[g,b]=L.useState(),k=n?.summary?.status==="requesting"||n?.summary?.status==="pending"||n?.summary?.status==="running",S=async()=>{if(!a)return;b(void 0);let j;if(d)try{j=XT(m)}catch(I){b(I instanceof Error?I.message:"Run input is invalid JSON");return}try{await o(a.workflowId,j)}catch(I){b(I instanceof Error?I.message:"Operator rejected the run")}};return v.jsxs("div",{className:"run-controls relative flex items-center gap-2 max-[700px]:flex-wrap [&_button:disabled]:cursor-wait [&_button:disabled]:opacity-50",children:[s&&v.jsxs("button",{type:"button",className:"workflow-view-button inline-flex cursor-pointer items-center gap-1.5 rounded-[7px] border border-line bg-white px-[11px] py-[7px] text-[10px] font-bold text-secondary hover:border-secondary hover:bg-[#f7f9f8] hover:text-ink [&_svg]:size-[11px]",title:"Leave this immutable run and view the current workflow",onClick:s,children:[v.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 12 12",fill:"none",children:v.jsx("path",{d:"M5 2 1.5 6 5 10M2 6h8",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round",strokeLinejoin:"round"})}),v.jsx("span",{children:"Current workflow"})]}),a&&v.jsxs(v.Fragment,{children:[v.jsxs("button",{type:"button",className:"run-button inline-flex cursor-pointer items-center gap-1.5 rounded-[7px] border border-acid bg-acid px-[11px] py-[7px] text-[10px] font-bold text-white hover:border-[#1d4ed8] hover:bg-[#1d4ed8] [&_svg]:size-[11px] [&_svg]:fill-current",onClick:()=>{S()},children:[v.jsx("svg",{"aria-hidden":"true",viewBox:"0 0 12 12",children:v.jsx("path",{d:"M2.5 1.5 10 6l-7.5 4.5z"})}),v.jsx("span",{children:"Run"})]}),v.jsx("button",{type:"button",className:`input-toggle cursor-pointer border-0 bg-transparent p-0.5 text-[9px] text-acid underline underline-offset-2 hover:text-[#1d4ed8] ${d?"active text-[#1d4ed8]":""}`,onClick:()=>h(j=>!j),children:d?"Hide JSON input":"Add JSON input"})]}),k&&n?.summary&&v.jsx("button",{type:"button",className:"cancel-button cursor-pointer rounded-[7px] border border-[#e0a6a1] bg-white px-[11px] py-[7px] text-[10px] text-[#a92f29] hover:bg-[#fff3f2]",disabled:i?.kind==="cancel",onClick:()=>{b(void 0),u(n.summary.runId).catch(j=>{b(j instanceof Error?j.message:"Cancellation failed")})},children:i?.kind==="cancel"?"Cancelling…":"Cancel run"}),d&&a&&v.jsxs("div",{className:"input-popover absolute right-0 bottom-[43px] z-20 w-[390px] rounded-[9px] border border-[#cbd2ce] bg-white p-[13px] shadow-[0_18px_50px_rgba(20,31,26,.16)] max-[700px]:w-[calc(100vw-32px)] [&>div:first-child]:mb-[9px] [&>div:first-child]:flex [&>div:first-child]:justify-between [&_strong]:text-[11px] [&_span]:font-mono [&_span]:text-[8px] [&_span]:text-[#6d7872]",children:[v.jsxs("div",{children:[v.jsx("strong",{children:"Workflow input"}),v.jsx("span",{children:"Schema-blind JSON object"})]}),v.jsx(FT,{value:m,onChange:p})]}),g&&v.jsx("div",{className:`action-error absolute right-0 z-[21] w-[390px] rounded-[7px] border border-[#efb9b5] bg-[#fff1f0] px-[18px] py-2 text-xs text-[#9d2923] max-[700px]:w-[calc(100vw-32px)] ${d?"bottom-[205px]":"bottom-11"}`,children:g})]})}const KT=32,$T=8,tg=new Intl.DateTimeFormat(void 0,{dateStyle:"short",timeStyle:"short"});function ZT(a,n){const i=BigInt(a.createdSequence),o=BigInt(n.createdSequence);return i===o?a.runId.localeCompare(n.runId):iObject.values(n).filter(h=>h.workflowId===a).sort(ZT),[n,a]),d=cy({count:s.length,getScrollElement:()=>u.current,estimateSize:()=>KT,getItemKey:h=>s[h].runId,overscan:$T});return v.jsxs("section",{className:"run-list-panel w-[300px] overflow-hidden rounded-[9px] border border-line bg-[rgba(255,255,255,.96)] shadow-[0_6px_20px_rgba(20,31,26,.1)]","aria-label":"Workflow runs",children:[v.jsxs("header",{className:"flex h-[30px] items-center justify-between border-b border-line px-[9px] [&_strong]:text-[10px] [&_span]:font-mono [&_span]:text-[8px] [&_span]:text-secondary",children:[v.jsx("strong",{children:"Runs"}),v.jsx("span",{children:s.length})]}),s.length?v.jsx("div",{className:"run-list-scroll max-h-48 overflow-auto",ref:u,children:v.jsx("div",{className:"run-list-virtual relative w-full",style:{height:d.getTotalSize()},children:d.getVirtualItems().map(h=>{const m=s[h.index],p=JT(m);return v.jsxs("button",{type:"button",className:`run-list-row absolute top-0 left-0 grid w-full cursor-pointer grid-cols-[8px_minmax(0,1fr)_auto_38px] grid-rows-[12px_12px] items-center gap-x-[7px] gap-y-0 border-0 border-b border-[#eef1ef] bg-transparent px-[9px] py-1 text-left text-ink leading-none hover:bg-[#f4f6f5] [&_code]:overflow-hidden [&_code]:text-ellipsis [&_code]:whitespace-nowrap [&_code]:text-[9px] [&_code]:text-[#36423c] ${i===m.runId?"active bg-[#edf3ff] shadow-[inset_2px_0_#2563eb]":""}`,onClick:()=>o(m.runId),style:{height:h.size,transform:`translateY(${h.start}px)`},"aria-label":`${m.runId}, ${m.status}, ${ng(m)}, ${p?tg.format(p):"trigger time not recorded"}`,children:[v.jsx("span",{className:`row-span-2 ${m.status==="requesting"?"bg-amber":m.status==="success"?"status-success bg-mint":m.status==="failed"?"status-failed bg-danger":m.status==="running"?"status-running bg-acid":"bg-muted"} size-[7px] rounded-full`,"aria-hidden":"true"}),v.jsx("code",{title:m.runId,children:m.runId}),v.jsx("span",{className:`run-status-text text-[8px] capitalize ${m.status==="requesting"?"text-amber":m.status==="success"?"status-success text-mint":m.status==="failed"?"status-failed text-danger":m.status==="running"?"status-running text-acid":""}`,children:m.status}),v.jsx("time",{className:"run-duration text-right font-mono text-[8px] text-secondary",children:ng(m)}),v.jsx("time",{className:"run-triggered-at col-start-2 col-end-5 font-mono text-[8px] text-secondary",dateTime:p?.toISOString(),children:p?tg.format(p):"Trigger time not recorded"})]},m.runId)})})}):v.jsx("span",{className:"run-list-empty block p-2.5 font-mono text-[8px] text-secondary",children:"No runs yet"})]})}const PT=1024,e2=256,lg=256,hy={runs:{},selectedRunStatus:"idle",liveEvents:{},liveLogs:{},liveEventRepairWatermarks:{},liveLogRepairWatermarks:{},operatorInstanceId:"",sequence:"0",connection:"connecting"};function ig(a,n,i){const o=BigInt(i(n));if(a.some(h=>BigInt(i(h))===o))return{items:a};let u=a.length;for(;u>0&&BigInt(i(a[u-1]))>o;)u-=1;const s=[...a.slice(0,u),n,...a.slice(u)];if(s.length<=lg)return{items:s};const d=s.length-lg;return{items:s.slice(d),droppedThrough:i(s[d-1])}}function ag(a,n){return a===void 0||BigInt(n)>BigInt(a)?n:a}function py(a,n,i){if(i.operatorInstanceId!==a.operatorInstanceId||i.summary?.runId!==n||BigInt(i.asOfSequence)=BigInt(o.revision)}function rg(a,n){const i=`${n}:`;return Object.fromEntries(Object.entries(a).filter(([o])=>!o.startsWith(i)))}function og(a,n){return Object.fromEntries(Object.entries(a).filter(([i])=>i!==n))}function t2(a,n){if(n.operatorInstanceId!==a.operatorInstanceId)throw new Error("Operator epoch changed");if(n.payload.oneofKind!=="update")throw new Error("Operator requested a structural reset");const i=n.payload.update;if(BigInt(i.sequence)!==BigInt(a.sequence)+1n)throw new Error(`Operator update gap after sequence ${a.sequence}`);const o={...a,sequence:i.sequence,error:void 0},u=i.change;if(u.oneofKind==="catalogReplaced")return u.catalogReplaced.catalog&&(o.catalog=u.catalogReplaced.catalog),o;if(u.oneofKind==="runCreated"&&u.runCreated.summary){const m=u.runCreated.summary;return o.runs={...a.runs,[m.runId]:m},o}const s=u.oneofKind==="runStatusChanged"?u.runStatusChanged.runId:u.oneofKind==="nodeStatusChanged"?u.nodeStatusChanged.runId:u.oneofKind==="logAppended"?u.logAppended.runId:u.oneofKind==="agentEventAppended"?u.agentEventAppended.runId:u.oneofKind==="traceFinalized"?u.traceFinalized.runId:"",d=a.selectedRunId===s?a.selectedRun:void 0,h=d&&BigInt(i.sequence)>BigInt(d.asOfSequence)?d:void 0;if(u.oneofKind==="runStatusChanged"){const m=u.runStatusChanged,p=a.runs[s];p&&(o.runs={...a.runs,[s]:{...p,status:m.status,startedAt:m.startedAt,endedAt:m.endedAt,revision:m.revision}}),h?.summary&&(o.selectedRun={...h,summary:{...h.summary,status:m.status,startedAt:m.startedAt,endedAt:m.endedAt,revision:m.revision}})}else if(u.oneofKind==="nodeStatusChanged"&&h){const m=u.nodeStatusChanged;o.selectedRun={...h,nodes:h.nodes.map(p=>p.nodeId===m.nodeId?{...p,status:m.status,startedAt:m.startedAt,endedAt:m.endedAt,revision:m.revision,error:m.error}:p)}}else if(u.oneofKind==="logAppended"&&a.selectedRunId===s&&(d===void 0||BigInt(i.sequence)>BigInt(d.asOfSequence))&&u.logAppended.log){const m=u.logAppended.log,p=s,g=ig(a.liveLogs[p]??[],m,b=>b.sequence);g.items!==a.liveLogs[p]&&(o.liveLogs={...a.liveLogs,[p]:g.items}),g.droppedThrough!==void 0&&(o.liveLogRepairWatermarks={...a.liveLogRepairWatermarks,[p]:ag(a.liveLogRepairWatermarks[p],g.droppedThrough)})}else if(u.oneofKind==="agentEventAppended"&&a.selectedRunId===s&&(d===void 0||BigInt(i.sequence)>BigInt(d.asOfSequence))&&u.agentEventAppended.event){const m=u.agentEventAppended.event,p=`${s}:${u.agentEventAppended.nodeId}`,g=ig(a.liveEvents[p]??[],m,b=>b.eventSequence);g.items!==a.liveEvents[p]&&(o.liveEvents={...a.liveEvents,[p]:g.items}),g.droppedThrough!==void 0&&(o.liveEventRepairWatermarks={...a.liveEventRepairWatermarks,[p]:ag(a.liveEventRepairWatermarks[p],g.droppedThrough)})}else u.oneofKind==="traceFinalized"&&h&&u.traceFinalized.trace&&(o.selectedRun={...h,nodes:h.nodes.map(m=>m.nodeId===u.traceFinalized.nodeId?{...m,trace:u.traceFinalized.trace}:m)});return o}function n2(a,n){if(n.type==="baseline")return{...hy,catalog:n.baseline.catalog,runs:Object.fromEntries(n.baseline.runs.map(o=>[o.runId,o])),operatorInstanceId:n.baseline.catalog.operatorInstanceId,sequence:n.baseline.asOfSequence,connection:"live"};if(n.type==="connection")return{...a,connection:n.connection,error:n.error};if(n.type==="action")return{...a,action:n.action};if(n.type==="selectionLoading")return{...a,selectedRunId:n.runId,selectedRun:void 0,selectedRunStatus:"loading",selectedRunError:void 0,liveEvents:{},liveLogs:{},liveEventRepairWatermarks:{},liveLogRepairWatermarks:{}};if(n.type==="selectionReady")return a.selectedRunId!==n.runId||!py(a,n.runId,n.snapshot)?a:{...a,selectedRunId:n.runId,selectedRun:n.snapshot,selectedRunStatus:"ready",selectedRunError:void 0,liveEvents:rg(a.liveEvents,n.runId),liveLogs:og(a.liveLogs,n.runId),liveEventRepairWatermarks:rg(a.liveEventRepairWatermarks,n.runId),liveLogRepairWatermarks:og(a.liveLogRepairWatermarks,n.runId)};if(n.type==="selectionError")return{...a,selectedRunId:n.runId,selectedRun:void 0,selectedRunStatus:"error",selectedRunError:n.error};if(n.type==="selectionCleared")return{...a,selectedRunId:void 0,selectedRun:void 0,selectedRunStatus:"idle",selectedRunError:void 0,liveEvents:{},liveLogs:{},liveEventRepairWatermarks:{},liveLogRepairWatermarks:{}};let i=a;for(const o of n.envelopes)i=t2(i,o);return i}function l2(a){const[n,i]=L.useReducer(n2,hy),o=L.useRef(n);o.current=n;const u=L.useRef({operatorInstanceId:n.operatorInstanceId,sequence:n.sequence});(u.current.operatorInstanceId!==n.operatorInstanceId||BigInt(n.sequence)>BigInt(u.current.sequence))&&(u.current={operatorInstanceId:n.operatorInstanceId,sequence:n.sequence});const s=L.useRef(void 0),d=L.useRef(void 0),h=L.useRef(0),m=L.useRef(void 0),p=L.useRef(void 0),g=L.useRef(void 0),b=L.useCallback(()=>{h.current+=1,d.current?.abort(),d.current=void 0},[]),k=L.useCallback(()=>{s.current?.abort(),g.current?.()},[]);L.useEffect(()=>{const B=new AbortController;let F=250;const te=re=>new Promise(ue=>{const de=()=>{p.current!==void 0&&window.clearTimeout(p.current),p.current=void 0,g.current===de&&(g.current=void 0),ue()};g.current=de,p.current=window.setTimeout(de,re)});return(async()=>{for(;!B.signal.aborted;){const re=new AbortController;s.current=re;let ue=[],de=0;const pe=()=>{ue=[],m.current!==void 0&&(window.cancelAnimationFrame(m.current),m.current=void 0)},le=()=>{m.current!==void 0||re.signal.aborted||(m.current=window.requestAnimationFrame(()=>{if(m.current=void 0,re.signal.aborted){ue=[];return}const Z=ue.splice(0,e2);if(Z.length>0){const me=Z[Z.length-1];me.payload.oneofKind==="update"&&(u.current={operatorInstanceId:me.operatorInstanceId,sequence:me.payload.update.sequence}),i({type:"envelopes",envelopes:Z})}ue.length>0&&le()}))};try{i({type:"connection",connection:"connecting"});const Z=await a.loadBaseline(re.signal);if(re.signal.aborted||B.signal.aborted)continue;b(),u.current={operatorInstanceId:Z.catalog.operatorInstanceId,sequence:Z.asOfSequence},i({type:"baseline",baseline:Z}),F=250;let me=Z.asOfSequence;for await(const ne of a.streamUpdates(Z.catalog.operatorInstanceId,me,re.signal)){if(re.signal.aborted||B.signal.aborted)break;if(ne.operatorInstanceId!==Z.catalog.operatorInstanceId||ne.payload.oneofKind!=="update"||BigInt(ne.payload.update.sequence)!==BigInt(me)+1n||ue.length>=PT){re.abort();break}ue.push(ne),me=ne.payload.update.sequence,le()}pe(),B.signal.aborted||i({type:"connection",connection:"reconnecting"})}catch(Z){pe(),!B.signal.aborted&&!re.signal.aborted&&(i({type:"connection",connection:"reconnecting",error:Z instanceof Error?Z.message:"Operator connection failed"}),de=F,F=Math.min(F*2,4e3))}finally{pe(),re.abort(),s.current===re&&(s.current=void 0)}de>0&&!B.signal.aborted&&await te(de)}})(),()=>{B.abort(),s.current?.abort(),m.current!==void 0&&(window.cancelAnimationFrame(m.current),m.current=void 0),g.current?.(),b()}},[b,a]);const S=L.useCallback(async(B,F)=>{b();const te=h.current,q=new AbortController;d.current=q;const re=o.current.operatorInstanceId;F&&i({type:"selectionLoading",runId:B});try{for(;!q.signal.aborted&&h.current===te;){const ue=await a.getLatestRunSnapshot(B,re,q.signal);if(q.signal.aborted||h.current!==te||o.current.operatorInstanceId!==re)return;if(!(u.current.operatorInstanceId!==re||BigInt(ue.asOfSequence){if(B===void 0){b(),i({type:"selectionCleared"});return}await S(B,!0)},[b,S]),I=n.selectedRunId,X=I&&n.selectedRunStatus==="ready"?[...Object.entries(n.liveEventRepairWatermarks).filter(([B])=>B.startsWith(`${I}:`)).sort(([B],[F])=>B.localeCompare(F)).map(([B,F])=>`${B}:${F}`),...n.liveLogRepairWatermarks[I]?[`${I}:${n.liveLogRepairWatermarks[I]}`]:[]].join("|"):"";L.useEffect(()=>{!I||!X||S(I,!1)},[S,X,I]);const D=L.useCallback(async(B,F)=>{i({type:"action",action:{kind:"start",target:B}});try{return await a.startRun(B,F)}finally{i({type:"action",action:void 0})}},[a]),G=L.useCallback(async B=>{i({type:"action",action:{kind:"cancel",target:B}});try{await a.cancelRun(B)}finally{i({type:"action",action:void 0})}},[a]);return{state:n,reconcile:k,startRun:D,cancelRun:G,selectRun:j}}const i2=new URL("/assets/avalanche-diamond-3d-1024-DG4CnLyY.png",import.meta.url).href,a2=220,r2=420,o2=280,s2=320,u2=640,c2=410,sg=16;function ug({className:a,label:n,controls:i,value:o,min:u,max:s,pointerDirection:d,onChange:h}){const m=L.useRef(void 0),p=b=>{m.current&&(b.currentTarget.hasPointerCapture?.(b.pointerId)&&b.currentTarget.releasePointerCapture(b.pointerId),m.current=void 0)},g=b=>{let k;b.key==="ArrowLeft"&&(k=o-sg*d),b.key==="ArrowRight"&&(k=o+sg*d),b.key==="Home"&&(k=u),b.key==="End"&&(k=s),k!==void 0&&(b.preventDefault(),h(Math.min(s,Math.max(u,k))))};return v.jsx("div",{className:`workspace-divider relative z-[4] min-h-0 min-w-0 cursor-col-resize touch-none bg-panel after:absolute after:inset-y-0 after:left-1/2 after:w-0.5 after:-translate-x-1/2 after:bg-line after:content-[''] after:transition-colors after:duration-150 hover:after:bg-acid focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-acid focus-visible:after:bg-acid ${a}`,role:"separator","aria-label":n,"aria-controls":i,"aria-orientation":"vertical","aria-valuemin":u,"aria-valuemax":s,"aria-valuenow":o,"aria-valuetext":`${o} pixels`,tabIndex:0,onKeyDown:g,onPointerDown:b=>{b.preventDefault(),m.current={clientX:b.clientX,value:o},b.currentTarget.setPointerCapture?.(b.pointerId)},onPointerMove:b=>{const k=m.current;if(!k)return;const S=k.value+(b.clientX-k.clientX)*d;h(Math.min(s,Math.max(u,S)))},onPointerUp:p,onPointerCancel:p})}function f2({api:a}){const{state:n,startRun:i,cancelRun:o,selectRun:u}=l2(a),[s,d]=L.useState(),[h,m]=L.useState(),[p,g]=L.useState(!1),[b,k]=L.useState(!1),[S,j]=L.useState(o2),[I,X]=L.useState(c2),D=L.useRef(n.selectedRunId);L.useEffect(()=>{const W=n.catalog?.workflows??[];if(!W.length){s&&(d(void 0),m(void 0),u(void 0));return}if(!s){d({kind:"workflow",workflowId:W[0].workflowId});return}W.some(w=>w.workflowId===s.workflowId)||(d({kind:"workflow",workflowId:W[0].workflowId}),m(void 0),u(void 0))},[u,s,n.catalog]),L.useEffect(()=>{const W=D.current;if(D.current=n.selectedRunId,s?.kind!=="run"||n.selectedRunId!==void 0||n.selectedRunStatus!=="idle"||W!==s.runId)return;if(n.runs[s.runId]){u(s.runId);return}const w=n.catalog?.workflows??[],ze=w.find(Se=>Se.workflowId===s.workflowId)??w[0];d(ze?{kind:"workflow",workflowId:ze.workflowId}:void 0),m(void 0),u(void 0)},[u,s,n.catalog,n.runs,n.selectedRunId,n.selectedRunStatus]),L.useEffect(()=>()=>{u(void 0)},[u]);const G=n.catalog?.workflows.find(W=>W.workflowId===s?.workflowId),B=s?.kind==="run",F=B&&n.selectedRunId===s.runId&&n.selectedRunStatus==="ready"&&n.selectedRun?.summary?.runId===s.runId?n.selectedRun:void 0,te=L.useCallback(W=>m(W),[]),q=L.useCallback(()=>m(void 0),[]),re=L.useCallback(()=>k(!0),[]),ue=L.useCallback(()=>k(!1),[]),de=L.useCallback(W=>{d(W),m(void 0),g(!1),u(W.kind==="run"?W.runId:void 0)},[u]),pe=L.useCallback(W=>{G&&de({kind:"run",workflowId:G.workflowId,runId:W})},[de,G]),le=L.useCallback(()=>{G&&de({kind:"workflow",workflowId:G.workflowId})},[de,G]),Z=b?v.jsx("button",{type:"button",className:"explorer-restore-button grid size-7 flex-none cursor-pointer place-items-center rounded-[7px] border border-line bg-white p-0 text-secondary hover:border-secondary hover:bg-[#f7f9f8] hover:text-ink focus-visible:outline-2 focus-visible:-outline-offset-2 focus-visible:outline-acid max-[700px]:hidden","aria-label":"Restore Explorer","aria-controls":"operator-explorer","aria-expanded":"false",onClick:ue,children:v.jsx(k1,{"aria-hidden":"true",className:"size-4",strokeWidth:1.8})}):void 0,me=G?v.jsxs(v.Fragment,{children:[Z,v.jsx(WT,{workflowId:G.workflowId,runs:n.runs,selectedRunId:B?s.runId:void 0,onSelectRun:pe})]}):void 0,$=!!G&&(!B||!!F)?v.jsx(QT,{workflow:B?void 0:G,run:F,pending:n.action,onStart:i,onCancel:o,onViewWorkflow:B?le:void 0}):void 0,R=B&&h?`${s.runId}:${h}`:"",K=!!(h&&(!B||F)),fe={"--workspace-explorer-width":`${S}px`,"--workspace-inspector-width":`${I}px`,"--workspace-explorer-column-width":b?"0px":`${S}px`,"--workspace-explorer-divider-width":"0px","--workspace-inspector-column-width":K?`${I}px`:"0px","--workspace-inspector-divider-width":"0px"};return v.jsxs("div",{className:`app-shell flex h-full flex-col ${p?"explorer-open":""} ${b?"explorer-collapsed":""}`,children:[v.jsxs("header",{className:"topbar relative z-10 grid min-h-[58px] grid-cols-[260px_minmax(0,1fr)_auto_auto] items-center border-b border-line bg-white px-5 shadow-[0_1px_2px_rgba(20,31,26,.04)] max-[1000px]:grid-cols-[210px_minmax(0,1fr)_auto_auto] max-[700px]:grid-cols-[auto_minmax(0,1fr)_auto] max-[700px]:gap-2 max-[700px]:px-2.5",children:[v.jsxs("div",{className:"brand flex items-center gap-[11px]",children:[v.jsx("img",{className:"brand-mark size-[30px] object-contain",src:i2,alt:""}),v.jsxs("div",{className:"flex items-baseline gap-[7px]",children:[v.jsx("strong",{className:"text-[15px] tracking-[-0.02em]",children:"Avalanche"}),v.jsx("span",{className:"font-mono text-[11px] text-muted uppercase",children:"Operator"})]})]}),v.jsxs("div",{className:"breadcrumb absolute left-1/2 flex -translate-x-1/2 justify-center gap-[9px] text-xs text-muted max-[700px]:hidden [&_i]:opacity-40 [&_strong]:font-semibold [&_strong]:text-[#26322c]",children:[v.jsx("span",{children:G?.rootAlias||"Local operator"}),G&&v.jsxs(v.Fragment,{children:[v.jsx("i",{children:"/"}),v.jsx("strong",{children:G.displayName})]}),B&&v.jsxs(v.Fragment,{children:[v.jsx("i",{children:"/"}),v.jsx("strong",{children:s.runId})]})]}),v.jsxs("div",{className:`connection flex items-center gap-2 font-mono text-[11px] capitalize [&>span]:size-[7px] [&>span]:rounded-full ${n.connection==="live"?"[&>span]:bg-mint":"[&>span]:bg-amber"} max-[700px]:justify-self-end connection-${n.connection}`,children:[v.jsx("span",{}),n.connection==="live"?"Live":n.connection]}),v.jsx("button",{type:"button",className:"explorer-toggle hidden cursor-pointer rounded-[7px] border border-[#cbd2ce] bg-white px-[9px] py-[7px] text-[10px] max-[700px]:block","aria-controls":"operator-explorer","aria-expanded":p,onClick:()=>g(W=>!W),children:"Explorer"})]}),n.error&&v.jsx("div",{className:"connection-error border-b border-[#efb9b5] bg-[#fff1f0] px-[18px] py-2 text-xs text-[#9d2923]",children:n.error}),v.jsxs("main",{className:`workspace grid min-h-0 w-full flex-1 overflow-hidden grid-cols-[var(--workspace-explorer-column-width)_var(--workspace-explorer-divider-width)_minmax(0,1fr)_var(--workspace-inspector-divider-width)_var(--workspace-inspector-column-width)] max-[1000px]:grid-cols-[var(--workspace-explorer-column-width)_var(--workspace-explorer-divider-width)_minmax(0,1fr)] max-[700px]:grid-cols-[minmax(0,1fr)] ${K?"with-inspector":""}`,style:fe,children:[v.jsx(_1,{catalog:n.catalog,selection:s,onSelect:de,onCollapse:re,open:p,collapsed:b}),!b&&v.jsx(ug,{className:"workspace-explorer-divider col-start-2 z-[5] w-4 -translate-x-1/2 max-[700px]:hidden",label:"Resize Explorer",controls:"operator-explorer",value:S,min:a2,max:r2,pointerDirection:1,onChange:j}),v.jsx("section",{className:"canvas-shell relative col-start-3 grid min-h-0 min-w-0 w-full grid-rows-[minmax(0,1fr)] overflow-hidden bg-[#f7f9f8] max-[700px]:col-start-1",children:v.jsx("div",{className:B?"canvas run-canvas relative flex min-h-0 min-w-0 w-full flex-col overflow-hidden bg-[radial-gradient(circle,#e1e4df_1px,transparent_1px),#fafaf8] bg-[length:24px_24px]":"canvas blueprint-canvas relative min-h-0 min-w-0 w-full overflow-hidden bg-white",children:B?F?v.jsxs(v.Fragment,{children:[v.jsxs("div",{className:"run-graph-shell relative min-h-0 min-w-0 flex-[1_1_auto] overflow-hidden",children:[v.jsx(dm,{runTopology:F.topology,runNodes:F.nodes,selectedNodeId:h,onClearNode:q,onOpenNode:te,topLeftPanel:me,bottomRightPanel:$}),v.jsxs("div",{className:"historical-badge absolute top-[18px] right-[18px] z-[5] rounded-lg border border-[#dfc99e] bg-[rgba(255,252,245,.96)] px-3 py-[9px] text-[9px] text-[#766548] shadow-[0_4px_14px_rgba(54,44,25,.08)] [&>span]:mb-[3px] [&>span]:block [&>span]:font-mono [&>span]:text-[8px] [&>span]:text-amber [&>span]:uppercase",children:[v.jsx("span",{children:"Immutable run snapshot"}),"Current workflow changes do not alter this canvas"]})]}),v.jsx(YT,{api:a,run:F,nodeId:h,liveLogs:n.liveLogs[s.runId],onSelectNode:te})]}):n.selectedRunId===s.runId&&n.selectedRunStatus==="loading"?v.jsxs(v.Fragment,{children:[Z,v.jsxs("div",{className:"empty-state grid h-full place-content-center text-center text-[#6d7872] [&>span]:text-[40px] [&>span]:text-acid [&>h2]:my-2 [&>h2]:text-[#27332d] [&>p]:max-w-[390px] [&>p]:text-xs",role:"status",children:[v.jsx("span",{children:"◇"}),v.jsx("h2",{children:"Loading run snapshot"}),v.jsx("p",{children:"Retrieving the retained topology and execution state."})]})]}):n.selectedRunId===s.runId&&n.selectedRunStatus==="error"?v.jsxs(v.Fragment,{children:[Z,v.jsxs("div",{className:"empty-state grid h-full place-content-center text-center text-[#6d7872] [&>span]:text-[40px] [&>span]:text-acid [&>h2]:my-2 [&>h2]:text-[#27332d] [&>p]:max-w-[390px] [&>p]:text-xs",role:"alert",children:[v.jsx("span",{children:"!"}),v.jsx("h2",{children:"Run snapshot unavailable"}),v.jsx("p",{children:n.selectedRunError||"The selected run could not be loaded."})]})]}):v.jsxs(v.Fragment,{children:[Z,v.jsxs("div",{className:"empty-state grid h-full place-content-center text-center text-[#6d7872] [&>span]:text-[40px] [&>span]:text-acid [&>h2]:my-2 [&>h2]:text-[#27332d] [&>p]:max-w-[390px] [&>p]:text-xs",children:[v.jsx("span",{children:"◇"}),v.jsx("h2",{children:"No run snapshot"}),v.jsx("p",{children:"Select the run again to load its retained topology."})]})]}):G?v.jsx(dm,{workflow:G,topLeftPanel:me,bottomRightPanel:$,selectedNodeId:h,onClearNode:q,onOpenNode:te}):v.jsxs(v.Fragment,{children:[Z,v.jsxs("div",{className:"empty-state grid h-full place-content-center text-center text-[#6d7872] [&>span]:text-[40px] [&>span]:text-acid [&>h2]:my-2 [&>h2]:text-[#27332d] [&>p]:max-w-[390px] [&>p]:text-xs",children:[v.jsx("span",{children:"◇"}),v.jsx("h2",{children:"No workflows discovered"}),v.jsx("p",{children:"Catalog changes will appear here as the operator scans configured targets."})]})]})})}),K&&v.jsxs(v.Fragment,{children:[v.jsx(ug,{className:"workspace-inspector-divider col-start-4 z-[5] w-4 -translate-x-1/2 max-[1000px]:fixed max-[1000px]:top-[58px] max-[1000px]:right-[calc(min(var(--workspace-inspector-width),100vw)-8px)] max-[1000px]:bottom-0 max-[1000px]:z-[31] max-[700px]:hidden",label:"Resize Inspector",controls:"operator-inspector",value:I,min:s2,max:u2,pointerDirection:-1,onChange:X}),v.jsx("div",{id:"operator-inspector",className:"workspace-inspector-pane col-start-5 grid min-h-0 min-w-0 overflow-hidden max-[1000px]:contents",children:v.jsx(pT,{api:a,workflow:G,run:F,nodeId:h,liveEvents:n.liveEvents[R],onClose:q})})]})]})]})}const my=document.getElementById("root");if(!my)throw new Error("Operator UI root element is missing");Z0.createRoot(my).render(v.jsx(L.StrictMode,{children:v.jsx(f2,{api:new c1})})); diff --git a/src/runtime/operator/web_assets/assets/index-DcFtrHor.css b/src/runtime/operator/web_assets/assets/index-DcFtrHor.css new file mode 100644 index 0000000..28ac0b8 --- /dev/null +++ b/src/runtime/operator/web_assets/assets/index-DcFtrHor.css @@ -0,0 +1 @@ +@layer properties{@supports (((-webkit-hyphens:none)) and (not (margin-trim:inline))) or ((-moz-orient:inline) and (not (color:rgb(from red r g b)))){*,:before,:after,::backdrop{--tw-translate-x:0;--tw-translate-y:0;--tw-translate-z:0;--tw-rotate-x:initial;--tw-rotate-y:initial;--tw-rotate-z:initial;--tw-skew-x:initial;--tw-skew-y:initial;--tw-border-style:solid;--tw-leading:initial;--tw-font-weight:initial;--tw-tracking:initial;--tw-shadow:0 0 #0000;--tw-shadow-color:initial;--tw-shadow-alpha:100%;--tw-inset-shadow:0 0 #0000;--tw-inset-shadow-color:initial;--tw-inset-shadow-alpha:100%;--tw-ring-color:initial;--tw-ring-shadow:0 0 #0000;--tw-inset-ring-color:initial;--tw-inset-ring-shadow:0 0 #0000;--tw-ring-inset:initial;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-offset-shadow:0 0 #0000;--tw-outline-style:solid;--tw-blur:initial;--tw-brightness:initial;--tw-contrast:initial;--tw-grayscale:initial;--tw-hue-rotate:initial;--tw-invert:initial;--tw-opacity:initial;--tw-saturate:initial;--tw-sepia:initial;--tw-drop-shadow:initial;--tw-drop-shadow-color:initial;--tw-drop-shadow-alpha:100%;--tw-drop-shadow-size:initial;--tw-duration:initial;--tw-ease:initial;--tw-content:""}}}@layer theme{:root,:host{--font-sans:Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;--font-mono:ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;--color-red-500:oklch(63.7% .237 25.331);--color-green-500:oklch(72.3% .219 149.579);--color-violet-500:oklch(60.6% .25 292.717);--color-white:#fff;--spacing:.25rem;--text-xs:.75rem;--text-xs--line-height:calc(1 / .75);--text-sm:.875rem;--text-sm--line-height:calc(1.25 / .875);--text-base:1rem;--text-base--line-height: 1.5 ;--text-lg:1.125rem;--text-lg--line-height:calc(1.75 / 1.125);--text-xl:1.25rem;--text-xl--line-height:calc(1.75 / 1.25);--font-weight-semibold:600;--font-weight-bold:700;--leading-tight:1.25;--radius-md:.375rem;--radius-lg:.5rem;--radius-xl:.75rem;--ease-out:cubic-bezier(0, 0, .2, 1);--animate-pulse:pulse 2s cubic-bezier(.4, 0, .6, 1) infinite;--default-transition-duration:.15s;--default-transition-timing-function:cubic-bezier(.4, 0, .2, 1);--default-font-family:var(--font-sans);--default-mono-font-family:var(--font-mono);--color-ink:#17211c;--color-canvas:#f6f8f7;--color-panel:#fff;--color-line:#dfe4e1;--color-muted:#68746e;--color-acid:#2563eb;--color-mint:#16805d;--color-amber:#a15c00;--color-danger:#c43d36;--color-secondary:#55615b;--color-success:var(--color-green-500);--color-failed:var(--color-red-500);--color-agent:var(--color-violet-500)}}@layer base{*,:after,:before,::backdrop{box-sizing:border-box;border:0 solid;margin:0;padding:0}::file-selector-button{box-sizing:border-box;border:0 solid;margin:0;padding:0}html,:host{-webkit-text-size-adjust:100%;tab-size:4;line-height:1.5;font-family:var(--default-font-family,-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji");font-feature-settings:var(--default-font-feature-settings,normal);font-variation-settings:var(--default-font-variation-settings,normal);-webkit-tap-highlight-color:transparent}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;-webkit-text-decoration:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,samp,pre{font-family:var(--default-mono-font-family,ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace);font-feature-settings:var(--default-mono-font-feature-settings,normal);font-variation-settings:var(--default-mono-font-variation-settings,normal);font-size:1em}small{font-size:80%}sub,sup{vertical-align:baseline;font-size:75%;line-height:0;position:relative}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}:-moz-focusring:where(:not(iframe)){outline:auto}progress{vertical-align:baseline}summary{display:list-item}ol,ul,menu{list-style:none}img,svg,video,canvas,audio,iframe,embed,object{vertical-align:middle;display:block}img,video{max-width:100%;height:auto}button,input,select,optgroup,textarea{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}::file-selector-button{font:inherit;font-feature-settings:inherit;font-variation-settings:inherit;letter-spacing:inherit;color:inherit;opacity:1;background-color:#0000;border-radius:0}:where(select:is([multiple],[size])) optgroup{font-weight:bolder}:where(select:is([multiple],[size])) optgroup option{padding-inline-start:20px}::file-selector-button{margin-inline-end:4px}::placeholder{opacity:1}@supports (not ((-webkit-appearance:-apple-pay-button))) or (contain-intrinsic-size:1px){::placeholder{color:currentColor}@supports (color:color-mix(in lab,red,red)){::placeholder{color:color-mix(in oklab,currentcolor 50%,transparent)}}}textarea{resize:vertical}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-date-and-time-value{min-height:1lh;text-align:inherit}::-webkit-datetime-edit{display:inline-flex}::-webkit-datetime-edit-fields-wrapper{padding:0}::-webkit-datetime-edit{padding-block:0}::-webkit-datetime-edit-year-field{padding-block:0}::-webkit-datetime-edit-month-field{padding-block:0}::-webkit-datetime-edit-day-field{padding-block:0}::-webkit-datetime-edit-hour-field{padding-block:0}::-webkit-datetime-edit-minute-field{padding-block:0}::-webkit-datetime-edit-second-field{padding-block:0}::-webkit-datetime-edit-millisecond-field{padding-block:0}::-webkit-datetime-edit-meridiem-field{padding-block:0}::-webkit-calendar-picker-indicator{line-height:1}:-moz-ui-invalid{box-shadow:none}button,input:where([type=button],[type=reset],[type=submit]){appearance:button}::file-selector-button{appearance:button}::-webkit-inner-spin-button{height:auto}::-webkit-outer-spin-button{height:auto}[hidden]:where(:not([hidden=until-found])){display:none!important}}@layer components{.node-card{transition:border-color .15s ease-out,box-shadow .15s ease-out,min-height .2s ease-out,padding .2s ease-out,transform .15s ease-out}.node-header,.node-title,.node-card-meta,.node-card-details{transition:max-height .2s ease-out,opacity .15s ease-out,padding .2s ease-out,border-color .2s ease-out,transform .2s ease-out,font-size .2s ease-out}.node-card-meta{opacity:1;max-height:3rem}.node-card-details{opacity:1;max-height:2000px}.node-card--compact{justify-content:center;gap:0;min-height:100px}.node-card--compact .node-header{text-align:center;justify-content:center;align-items:center;gap:0;min-height:0;padding-right:0}.node-card--compact .node-card-meta{opacity:0;pointer-events:none;max-height:0}.node-card--compact .node-card-details{opacity:0;pointer-events:none;border-top-color:#0000;gap:0;min-height:0;max-height:0;padding-top:0}.node-card--compact .node-title{overflow-wrap:anywhere;text-align:center;-webkit-line-clamp:2;-webkit-box-orient:vertical;max-width:100%;display:-webkit-box;overflow:hidden;transform:none}@media(prefers-reduced-motion:reduce){.node-card,.node-header,.node-title,.node-card-meta,.node-card-details{transition:none}}}@layer utilities{.pointer-events-none{pointer-events:none}.invisible{visibility:hidden}.visible{visibility:visible}.absolute{position:absolute}.fixed{position:fixed}.relative{position:relative}.inset-0{inset:0}.-top-1{top:calc(var(--spacing) * -1)}.top-0{top:0}.top-3{top:calc(var(--spacing) * 3)}.top-4{top:calc(var(--spacing) * 4)}.top-\[18px\]{top:18px}.top-\[19px\]{top:19px}.top-\[58px\]{top:58px}.right-0{right:0}.right-3{right:calc(var(--spacing) * 3)}.right-3\.5{right:calc(var(--spacing) * 3.5)}.right-4{right:calc(var(--spacing) * 4)}.right-\[18px\]{right:18px}.bottom-0{bottom:0}.bottom-11{bottom:calc(var(--spacing) * 11)}.bottom-\[17px\]{bottom:17px}.bottom-\[43px\]{bottom:43px}.bottom-\[205px\]{bottom:205px}.left-0{left:0}.left-1\/2{left:50%}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-\[2\]{z-index:2}.z-\[4\]{z-index:4}.z-\[5\]{z-index:5}.z-\[6\]{z-index:6}.z-\[21\]{z-index:21}.col-start-1{grid-column-start:1}.col-start-2{grid-column-start:2}.col-start-3{grid-column-start:3}.col-start-4{grid-column-start:4}.col-start-5{grid-column-start:5}.col-end-5{grid-column-end:5}.row-span-2{grid-row:span 2/span 2}.container{width:100%}@media(min-width:40rem){.container{max-width:40rem}}@media(min-width:48rem){.container{max-width:48rem}}@media(min-width:64rem){.container{max-width:64rem}}@media(min-width:80rem){.container{max-width:80rem}}@media(min-width:96rem){.container{max-width:96rem}}.m-0{margin:0}.m-3\.5{margin:calc(var(--spacing) * 3.5)}.mx-2\.5{margin-inline:calc(var(--spacing) * 2.5)}.mx-3{margin-inline:calc(var(--spacing) * 3)}.my-2{margin-block:calc(var(--spacing) * 2)}.mt-0{margin-top:0}.mt-1{margin-top:var(--spacing)}.mt-2{margin-top:calc(var(--spacing) * 2)}.mt-\[3px\]{margin-top:3px}.mt-\[5px\]{margin-top:5px}.mb-0\!{margin-bottom:0!important}.mb-1\.5{margin-bottom:calc(var(--spacing) * 1.5)}.mb-2\.5{margin-bottom:calc(var(--spacing) * 2.5)}.mb-3{margin-bottom:calc(var(--spacing) * 3)}.mb-\[5px\]{margin-bottom:5px}.ml-1{margin-left:var(--spacing)}.ml-auto{margin-left:auto}.line-clamp-2{-webkit-line-clamp:2;-webkit-box-orient:vertical;display:-webkit-box;overflow:hidden}.block{display:block}.contents{display:contents}.flex{display:flex}.grid{display:grid}.hidden{display:none}.inline{display:inline}.inline-block{display:inline-block}.inline-flex{display:inline-flex}.size-3{width:calc(var(--spacing) * 3);height:calc(var(--spacing) * 3)}.size-4{width:calc(var(--spacing) * 4);height:calc(var(--spacing) * 4)}.size-6{width:calc(var(--spacing) * 6);height:calc(var(--spacing) * 6)}.size-7{width:calc(var(--spacing) * 7);height:calc(var(--spacing) * 7)}.size-\[7px\]{width:7px;height:7px}.size-\[30px\]{width:30px;height:30px}.size-full{width:100%;height:100%}.size-px\!{width:1px!important;height:1px!important}.h-\[9px\]{height:9px}.h-\[30px\]{height:30px}.h-\[222px\]{height:222px}.h-full{height:100%}.max-h-0\!{max-height:0!important}.max-h-48{max-height:calc(var(--spacing) * 48)}.max-h-\[75\%\]{max-height:75%}.min-h-0{min-height:0}.min-h-0\!{min-height:0!important}.min-h-3\.5{min-height:calc(var(--spacing) * 3.5)}.min-h-9{min-height:calc(var(--spacing) * 9)}.min-h-10{min-height:calc(var(--spacing) * 10)}.min-h-48{min-height:calc(var(--spacing) * 48)}.min-h-\[58px\]{min-height:58px}.min-h-\[100px\]{min-height:100px}.min-h-\[130px\]{min-height:130px}.min-h-\[140px\]{min-height:140px}.min-h-full{min-height:100%}.w-4{width:calc(var(--spacing) * 4)}.w-\[300px\]{width:300px}.w-\[360px\]{width:360px}.w-\[390px\]{width:390px}.w-\[min\(var\(--workspace-inspector-width\)\,100vw\)\]{width:min(var(--workspace-inspector-width),100vw)}.w-full{width:100%}.max-w-full{max-width:100%}.min-w-0{min-width:0}.min-w-0\!{min-width:0!important}.min-w-48{min-width:calc(var(--spacing) * 48)}.min-w-80{min-width:calc(var(--spacing) * 80)}.flex-1{flex:1}.flex-\[0_0_35px\]{flex:0 0 35px}.flex-\[1_0_auto\]{flex:1 0 auto}.flex-\[1_1_auto\]{flex:auto}.flex-none{flex:none}.-translate-x-1\/2{--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.transform{transform:var(--tw-rotate-x,) var(--tw-rotate-y,) var(--tw-rotate-z,) var(--tw-skew-x,) var(--tw-skew-y,)}.cursor-col-resize{cursor:col-resize}.cursor-ns-resize{cursor:ns-resize}.cursor-pointer{cursor:pointer}.touch-none{touch-action:none}.resize{resize:both}.list-none{list-style-type:none}.grid-cols-2{grid-template-columns:repeat(2,minmax(0,1fr))}.grid-cols-\[8px_minmax\(0\,1fr\)_auto_38px\]{grid-template-columns:8px minmax(0,1fr) auto 38px}.grid-cols-\[23px_minmax\(0\,1fr\)\]{grid-template-columns:23px minmax(0,1fr)}.grid-cols-\[78px_minmax\(120px\,180px\)_52px_minmax\(12rem\,1fr\)\]{grid-template-columns:78px minmax(120px,180px) 52px minmax(12rem,1fr)}.grid-cols-\[260px_minmax\(0\,1fr\)_auto_auto\]{grid-template-columns:260px minmax(0,1fr) auto auto}.grid-cols-\[fit-content\(12rem\)_\.55rem_minmax\(12rem\,1fr\)\]{grid-template-columns:fit-content(12rem) .55rem minmax(12rem,1fr)}.grid-cols-\[minmax\(0\,1fr\)_minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.grid-cols-\[var\(--workspace-explorer-column-width\)_var\(--workspace-explorer-divider-width\)_minmax\(0\,1fr\)_var\(--workspace-inspector-divider-width\)_var\(--workspace-inspector-column-width\)\]{grid-template-columns:var(--workspace-explorer-column-width) var(--workspace-explorer-divider-width) minmax(0,1fr) var(--workspace-inspector-divider-width) var(--workspace-inspector-column-width)}.grid-rows-\[12px_12px\]{grid-template-rows:12px 12px}.grid-rows-\[35px_minmax\(0\,1fr\)\]{grid-template-rows:35px minmax(0,1fr)}.grid-rows-\[auto_auto_auto_minmax\(0\,1fr\)_auto\]{grid-template-rows:auto auto auto minmax(0,1fr) auto}.grid-rows-\[auto_auto_minmax\(0\,1fr\)\]{grid-template-rows:auto auto minmax(0,1fr)}.grid-rows-\[auto_minmax\(0\,1fr\)\]{grid-template-rows:auto minmax(0,1fr)}.grid-rows-\[minmax\(0\,1fr\)\]{grid-template-rows:minmax(0,1fr)}.flex-col{flex-direction:column}.flex-wrap{flex-wrap:wrap}.place-content-center{place-content:center}.place-items-center{place-items:center}.items-baseline{align-items:baseline}.items-center{align-items:center}.items-start{align-items:flex-start}.items-stretch{align-items:stretch}.justify-between{justify-content:space-between}.justify-center{justify-content:center}.justify-end{justify-content:flex-end}.justify-start{justify-content:flex-start}.gap-0{gap:0}.gap-0\!{gap:0!important}.gap-1{gap:var(--spacing)}.gap-1\.5{gap:calc(var(--spacing) * 1.5)}.gap-2{gap:calc(var(--spacing) * 2)}.gap-2\.5{gap:calc(var(--spacing) * 2.5)}.gap-3{gap:calc(var(--spacing) * 3)}.gap-6{gap:calc(var(--spacing) * 6)}.gap-\[5px\]{gap:5px}.gap-\[7px\]{gap:7px}.gap-\[9px\]{gap:9px}.gap-\[11px\]{gap:11px}.gap-x-0\.5{column-gap:calc(var(--spacing) * .5)}.gap-x-\[7px\]{column-gap:7px}.gap-y-0{row-gap:0}.self-stretch{align-self:stretch}.justify-self-start{justify-self:flex-start}.truncate{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.overflow-auto{overflow:auto}.overflow-hidden{overflow:hidden}.overflow-x-auto{overflow-x:auto}.rounded-\[7px\]{border-radius:7px}.rounded-\[9px\]{border-radius:9px}.rounded-\[inherit\]{border-radius:inherit}.rounded-full{border-radius:3.40282e38px}.rounded-lg{border-radius:var(--radius-lg)}.rounded-md{border-radius:var(--radius-md)}.rounded-xl{border-radius:var(--radius-xl)}.border{border-style:var(--tw-border-style);border-width:1px}.border\!{border-style:var(--tw-border-style)!important;border-width:1px!important}.border-0{border-style:var(--tw-border-style);border-width:0}.border-0\!{border-style:var(--tw-border-style)!important;border-width:0!important}.border-\[3px\]{border-style:var(--tw-border-style);border-width:3px}.border-t{border-top-style:var(--tw-border-style);border-top-width:1px}.border-r-0{border-right-style:var(--tw-border-style);border-right-width:0}.border-b{border-bottom-style:var(--tw-border-style);border-bottom-width:1px}.border-b-2{border-bottom-style:var(--tw-border-style);border-bottom-width:2px}.border-l{border-left-style:var(--tw-border-style);border-left-width:1px}.border-\[\#cbd2ce\]{border-color:#cbd2ce}.border-\[\#dfc99e\]{border-color:#dfc99e}.border-\[\#e0a6a1\]{border-color:#e0a6a1}.border-\[\#ead1a2\]{border-color:#ead1a2}.border-\[\#edf0ee\]{border-color:#edf0ee}.border-\[\#eef1ef\]{border-color:#eef1ef}.border-\[\#efb9b5\]{border-color:#efb9b5}.border-acid{border-color:var(--color-acid)}.border-acid\!{border-color:var(--color-acid)!important}.border-danger{border-color:var(--color-danger)}.border-line{border-color:var(--color-line)}.border-line\!{border-color:var(--color-line)!important}.border-mint{border-color:var(--color-mint)}.border-transparent{border-color:#0000}.border-t-transparent\!{border-top-color:#0000!important}.bg-\[\#edf3ff\]{background-color:#edf3ff}.bg-\[\#f1f4f2\]{background-color:#f1f4f2}.bg-\[\#f7f9f8\]{background-color:#f7f9f8}.bg-\[\#fbfcfb\]{background-color:#fbfcfb}.bg-\[\#fff1f0\]{background-color:#fff1f0}.bg-\[\#fff8eb\]{background-color:#fff8eb}.bg-\[radial-gradient\(circle\,\#e1e4df_1px\,transparent_1px\)\,\#fafaf8\]{background-color:radial-gradient(circle,#e1e4df 1px,transparent 1px),#fafaf8}.bg-\[rgba\(255\,252\,245\,\.96\)\]{background-color:#fffcf5f5}.bg-\[rgba\(255\,255\,255\,\.96\)\]{background-color:#fffffff5}.bg-\[rgba\(255\,255\,255\,\.98\)\]{background-color:#fffffffa}.bg-acid{background-color:var(--color-acid)}.bg-amber{background-color:var(--color-amber)}.bg-canvas{background-color:var(--color-canvas)}.bg-danger{background-color:var(--color-danger)}.bg-mint{background-color:var(--color-mint)}.bg-muted{background-color:var(--color-muted)}.bg-panel{background-color:var(--color-panel)}.bg-transparent{background-color:#0000}.bg-transparent\!{background-color:#0000!important}.bg-white{background-color:var(--color-white)}.bg-white\!{background-color:var(--color-white)!important}.bg-\[length\:24px_24px\]{background-size:24px 24px}.object-contain{object-fit:contain}.p-0{padding:0}.p-0\.5{padding:calc(var(--spacing) * .5)}.p-2{padding:calc(var(--spacing) * 2)}.p-2\.5{padding:calc(var(--spacing) * 2.5)}.p-4{padding:calc(var(--spacing) * 4)}.p-5{padding:calc(var(--spacing) * 5)}.p-\[7px\]{padding:7px}.p-\[9px\]{padding:9px}.p-\[13px\]{padding:13px}.px-0{padding-inline:0}.px-2{padding-inline:calc(var(--spacing) * 2)}.px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.px-3{padding-inline:calc(var(--spacing) * 3)}.px-4{padding-inline:calc(var(--spacing) * 4)}.px-5{padding-inline:calc(var(--spacing) * 5)}.px-\[7px\]{padding-inline:7px}.px-\[9px\]{padding-inline:9px}.px-\[11px\]{padding-inline:11px}.px-\[18px\]{padding-inline:18px}.py-1{padding-block:var(--spacing)}.py-1\.5{padding-block:calc(var(--spacing) * 1.5)}.py-2{padding-block:calc(var(--spacing) * 2)}.py-2\.5{padding-block:calc(var(--spacing) * 2.5)}.py-3{padding-block:calc(var(--spacing) * 3)}.py-\[3px\]{padding-block:3px}.py-\[5px\]{padding-block:5px}.py-\[7px\]{padding-block:7px}.py-\[9px\]{padding-block:9px}.pt-0\!{padding-top:0!important}.pt-2{padding-top:calc(var(--spacing) * 2)}.pt-2\.5{padding-top:calc(var(--spacing) * 2.5)}.pt-\[11px\]{padding-top:11px}.pt-\[18px\]{padding-top:18px}.pt-\[19px\]{padding-top:19px}.pt-\[22px\]{padding-top:22px}.pr-0{padding-right:0}.pr-\[76px\]{padding-right:76px}.pb-3\.5{padding-bottom:calc(var(--spacing) * 3.5)}.pb-\[9px\]{padding-bottom:9px}.pb-\[30px\]{padding-bottom:30px}.pl-3{padding-left:calc(var(--spacing) * 3)}.text-center{text-align:center}.text-left{text-align:left}.text-right{text-align:right}.align-\[-0\.08em\]{vertical-align:-.08em}.align-\[-0\.15em\]{vertical-align:-.15em}.font-mono{font-family:var(--font-mono)}.font-sans{font-family:var(--font-sans)}.text-\[7px\]\/\[1\.35\]{font-size:7px;line-height:1.35}.text-\[9px\]\/\[1\.45\]{font-size:9px;line-height:1.45}.text-base{font-size:var(--text-base);line-height:var(--tw-leading,var(--text-base--line-height))}.text-lg{font-size:var(--text-lg);line-height:var(--tw-leading,var(--text-lg--line-height))}.text-sm{font-size:var(--text-sm);line-height:var(--tw-leading,var(--text-sm--line-height))}.text-xl{font-size:var(--text-xl);line-height:var(--tw-leading,var(--text-xl--line-height))}.text-xs{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.text-\[7px\]{font-size:7px}.text-\[8px\]{font-size:8px}.text-\[9px\]{font-size:9px}.text-\[10px\]{font-size:10px}.text-\[11px\]{font-size:11px}.text-\[15px\]{font-size:15px}.text-\[17px\]{font-size:17px}.leading-\[1\.35\]{--tw-leading:1.35;line-height:1.35}.leading-\[1\.55\]{--tw-leading:1.55;line-height:1.55}.leading-\[1\.65\]{--tw-leading:1.65;line-height:1.65}.leading-none{--tw-leading:1;line-height:1}.leading-tight{--tw-leading:var(--leading-tight);line-height:var(--leading-tight)}.font-bold{--tw-font-weight:var(--font-weight-bold);font-weight:var(--font-weight-bold)}.tracking-\[-0\.02em\]{--tw-tracking:-.02em;letter-spacing:-.02em}.tracking-\[\.12em\]{--tw-tracking:.12em;letter-spacing:.12em}.tracking-\[\.16em\]{--tw-tracking:.16em;letter-spacing:.16em}.\[overflow-wrap\:anywhere\]{overflow-wrap:anywhere}.text-ellipsis{text-overflow:ellipsis}.whitespace-normal{white-space:normal}.whitespace-nowrap{white-space:nowrap}.whitespace-pre-wrap{white-space:pre-wrap}.text-\[\#1d4ed8\]{color:#1d4ed8}.text-\[\#6d7872\]{color:#6d7872}.text-\[\#9d2923\]{color:#9d2923}.text-\[\#36423c\]{color:#36423c}.text-\[\#766548\]{color:#766548}.text-\[\#a92f29\]{color:#a92f29}.text-acid{color:var(--color-acid)}.text-agent{color:var(--color-agent)}.text-amber{color:var(--color-amber)}.text-danger{color:var(--color-danger)}.text-failed{color:var(--color-failed)}.text-ink{color:var(--color-ink)}.text-mint{color:var(--color-mint)}.text-muted{color:var(--color-muted)}.text-secondary{color:var(--color-secondary)}.text-success{color:var(--color-success)}.text-white{color:var(--color-white)}.capitalize{text-transform:capitalize}.uppercase{text-transform:uppercase}.italic{font-style:italic}.line-through{text-decoration-line:line-through}.underline{text-decoration-line:underline}.underline-offset-2{text-underline-offset:2px}.opacity-0{opacity:0}.shadow-\[-20px_0_50px_rgba\(20\,31\,26\,\.14\)\]{--tw-shadow:-20px 0 50px var(--tw-shadow-color,#141f1a24);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_-5px_18px_rgba\(20\,31\,26\,\.08\)\]{--tw-shadow:0 -5px 18px var(--tw-shadow-color,#141f1a14);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_1px_2px_rgba\(20\,31\,26\,\.04\)\]{--tw-shadow:0 1px 2px var(--tw-shadow-color,#141f1a0a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_4px_14px_rgba\(20\,31\,26\,\.08\)\]\!{--tw-shadow:0 4px 14px var(--tw-shadow-color,#141f1a14)!important;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)!important}.shadow-\[0_4px_14px_rgba\(54\,44\,25\,\.08\)\]{--tw-shadow:0 4px 14px var(--tw-shadow-color,#362c1914);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_6px_20px_rgba\(20\,31\,26\,\.1\)\]{--tw-shadow:0 6px 20px var(--tw-shadow-color,#141f1a1a);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_8px_24px_rgba\(25\,39\,32\,\.08\)\]{--tw-shadow:0 8px 24px var(--tw-shadow-color,#19272014);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[0_18px_50px_rgba\(20\,31\,26\,\.16\)\]{--tw-shadow:0 18px 50px var(--tw-shadow-color,#141f1a29);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.shadow-\[inset_2px_0_\#2563eb\]{--tw-shadow:inset 2px 0 var(--tw-shadow-color,#2563eb);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.outline{outline-style:var(--tw-outline-style);outline-width:1px}.filter{filter:var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,)}.transition-\[border-color\,box-shadow\,transform\]{transition-property:border-color,box-shadow,transform;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[font-size\]{transition-property:font-size;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.transition-\[width\,height\]{transition-property:width,height;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.duration-150{--tw-duration:.15s;transition-duration:.15s}.duration-200{--tw-duration:.2s;transition-duration:.2s}.ease-out{--tw-ease:var(--ease-out);transition-timing-function:var(--ease-out)}.select-none{-webkit-user-select:none;user-select:none}.\[font-synthesis\:none\]{font-synthesis:none}.\[font\:inherit\]{font:inherit}.before\:pointer-events-none:before{content:var(--tw-content);pointer-events:none}.before\:absolute:before{content:var(--tw-content);position:absolute}.before\:inset-y-3:before{content:var(--tw-content);inset-block:calc(var(--spacing) * 3)}.before\:left-0:before{content:var(--tw-content);left:0}.before\:w-\[3px\]:before{content:var(--tw-content);width:3px}.before\:rounded-r-full:before{content:var(--tw-content);border-top-right-radius:3.40282e38px;border-bottom-right-radius:3.40282e38px}.before\:bg-agent:before{content:var(--tw-content);background-color:var(--color-agent)}.before\:content-\[\'\'\]:before{--tw-content:"";content:var(--tw-content)}.after\:absolute:after{content:var(--tw-content);position:absolute}.after\:inset-y-0:after{content:var(--tw-content);inset-block:0}.after\:top-\[3px\]:after{content:var(--tw-content);top:3px}.after\:right-0:after{content:var(--tw-content);right:0}.after\:left-0:after{content:var(--tw-content);left:0}.after\:left-1\/2:after{content:var(--tw-content);left:50%}.after\:h-0\.5:after{content:var(--tw-content);height:calc(var(--spacing) * .5)}.after\:w-0\.5:after{content:var(--tw-content);width:calc(var(--spacing) * .5)}.after\:-translate-x-1\/2:after{content:var(--tw-content);--tw-translate-x: -50% ;translate:var(--tw-translate-x) var(--tw-translate-y)}.after\:bg-line:after{content:var(--tw-content);background-color:var(--color-line)}.after\:transition-colors:after{content:var(--tw-content);transition-property:color,background-color,border-color,outline-color,text-decoration-color,fill,stroke,--tw-gradient-from,--tw-gradient-via,--tw-gradient-to;transition-timing-function:var(--tw-ease,var(--default-transition-timing-function));transition-duration:var(--tw-duration,var(--default-transition-duration))}.after\:duration-150:after{content:var(--tw-content);--tw-duration:.15s;transition-duration:.15s}.after\:content-\[\'\'\]:after{--tw-content:"";content:var(--tw-content)}.first\:border-t-0:first-child{border-top-style:var(--tw-border-style);border-top-width:0}@media(hover:hover){.hover\:-translate-y-px:hover{--tw-translate-y:-1px;translate:var(--tw-translate-x) var(--tw-translate-y)}.hover\:border-\[\#1d4ed8\]:hover{border-color:#1d4ed8}.hover\:border-acid:hover{border-color:var(--color-acid)}.hover\:border-secondary:hover{border-color:var(--color-secondary)}.hover\:bg-\[\#1d4ed8\]:hover{background-color:#1d4ed8}.hover\:bg-\[\#f1f4f2\]:hover{background-color:#f1f4f2}.hover\:bg-\[\#f4f6f5\]:hover{background-color:#f4f6f5}.hover\:bg-\[\#f7f9f8\]:hover{background-color:#f7f9f8}.hover\:bg-\[\#fff3f2\]:hover{background-color:#fff3f2}.hover\:bg-panel:hover{background-color:var(--color-panel)}.hover\:text-\[\#1d4ed8\]:hover{color:#1d4ed8}.hover\:text-ink:hover{color:var(--color-ink)}.hover\:shadow-\[0_10px_28px_rgba\(25\,39\,32\,\.12\)\]:hover{--tw-shadow:0 10px 28px var(--tw-shadow-color,#1927201f);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}.hover\:after\:bg-acid:hover:after{content:var(--tw-content);background-color:var(--color-acid)}}.focus-visible\:outline-2:focus-visible{outline-style:var(--tw-outline-style);outline-width:2px}.focus-visible\:outline-3:focus-visible{outline-style:var(--tw-outline-style);outline-width:3px}.focus-visible\:-outline-offset-2:focus-visible{outline-offset:-2px}.focus-visible\:outline-offset-2:focus-visible{outline-offset:2px}.focus-visible\:outline-offset-3:focus-visible{outline-offset:3px}.focus-visible\:outline-acid:focus-visible{outline-color:var(--color-acid)}.focus-visible\:after\:bg-acid:focus-visible:after{content:var(--tw-content);background-color:var(--color-acid)}.disabled\:cursor-wait:disabled{cursor:wait}.disabled\:text-muted:disabled{color:var(--color-muted)}@media(prefers-reduced-motion:reduce){.motion-reduce\:transition-none{transition-property:none}}@media not all and (min-width:1000px){.max-\[1000px\]\:fixed{position:fixed}.max-\[1000px\]\:top-\[58px\]{top:58px}.max-\[1000px\]\:right-\[calc\(min\(var\(--workspace-inspector-width\)\,100vw\)-8px\)\]{right:calc(min(var(--workspace-inspector-width),100vw) - 8px)}.max-\[1000px\]\:bottom-0{bottom:0}.max-\[1000px\]\:z-\[31\]{z-index:31}.max-\[1000px\]\:contents{display:contents}.max-\[1000px\]\:grid-cols-\[210px_minmax\(0\,1fr\)_auto_auto\]{grid-template-columns:210px minmax(0,1fr) auto auto}.max-\[1000px\]\:grid-cols-\[var\(--workspace-explorer-column-width\)_var\(--workspace-explorer-divider-width\)_minmax\(0\,1fr\)\]{grid-template-columns:var(--workspace-explorer-column-width) var(--workspace-explorer-divider-width) minmax(0,1fr)}}@media not all and (min-width:700px){.max-\[700px\]\:visible{visibility:visible}.max-\[700px\]\:fixed{position:fixed}.max-\[700px\]\:top-\[58px\]{top:58px}.max-\[700px\]\:bottom-0{bottom:0}.max-\[700px\]\:left-0{left:0}.max-\[700px\]\:z-\[31\]{z-index:31}.max-\[700px\]\:col-start-1{grid-column-start:1}.max-\[700px\]\:block{display:block}.max-\[700px\]\:hidden{display:none}.max-\[700px\]\:w-\[calc\(100vw-32px\)\]{width:calc(100vw - 32px)}.max-\[700px\]\:w-\[min\(320px\,100vw\)\]{width:min(320px,100vw)}.max-\[700px\]\:w-screen{width:100vw}.max-\[700px\]\:grid-cols-\[auto_minmax\(0\,1fr\)_auto\]{grid-template-columns:auto minmax(0,1fr) auto}.max-\[700px\]\:grid-cols-\[minmax\(0\,1fr\)\]{grid-template-columns:minmax(0,1fr)}.max-\[700px\]\:flex-wrap{flex-wrap:wrap}.max-\[700px\]\:gap-2{gap:calc(var(--spacing) * 2)}.max-\[700px\]\:justify-self-end{justify-self:flex-end}.max-\[700px\]\:overflow-auto{overflow:auto}.max-\[700px\]\:border-r{border-right-style:var(--tw-border-style);border-right-width:1px}.max-\[700px\]\:border-line{border-color:var(--color-line)}.max-\[700px\]\:px-2\.5{padding-inline:calc(var(--spacing) * 2.5)}.max-\[700px\]\:shadow-\[18px_0_45px_rgba\(20\,31\,26\,\.16\)\]{--tw-shadow:18px 0 45px var(--tw-shadow-color,#141f1a29);box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}@media(min-width:1001px){.min-\[1001px\]\:static{position:static}.min-\[1001px\]\:z-auto{z-index:auto}.min-\[1001px\]\:w-auto{width:auto}.min-\[1001px\]\:shadow-none{--tw-shadow:0 0 #0000;box-shadow:var(--tw-inset-shadow),var(--tw-inset-ring-shadow),var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow)}}.\[\&_\.react-flow__arrowhead_polyline\]\:fill-\[\#87938d\] .react-flow arrowhead polyline{fill:#87938d}.\[\&_\.react-flow__arrowhead_polyline\]\:stroke-\[\#87938d\] .react-flow arrowhead polyline{stroke:#87938d}.\[\&_\.react-flow__controls-button\]\:border-b-line\! .react-flow controls-button{border-bottom-color:var(--color-line)!important}.\[\&_\.react-flow__controls-button\]\:bg-white\! .react-flow controls-button{background-color:var(--color-white)!important}.\[\&_\.react-flow__controls-button\]\:fill-secondary\! .react-flow controls-button{fill:var(--color-secondary)!important}.\[\&_\.react-flow__controls-button\:hover\]\:bg-\[\#f1f4f2\]\! .react-flow controls-button:hover{background-color:#f1f4f2!important}.\[\&_\.react-flow__edge-path\]\:stroke-\[\#87938d\] .react-flow edge-path{stroke:#87938d}.\[\&_\.react-flow__edge-path\]\:\[stroke-width\:1\.4\] .react-flow edge-path{stroke-width:1.4px}.\[\&_\.run-list-panel\]\:h-\[222px\] .run-list-panel{height:222px}.\[\&_button\:disabled\]\:cursor-wait button:disabled{cursor:wait}.\[\&_button\:disabled\]\:opacity-50 button:disabled{opacity:.5}.\[\&_code\]\:mt-0\.5 code{margin-top:calc(var(--spacing) * .5)}.\[\&_code\]\:mt-\[3px\] code{margin-top:3px}.\[\&_code\]\:block code{display:block}.\[\&_code\]\:overflow-hidden code{overflow:hidden}.\[\&_code\]\:font-mono code{font-family:var(--font-mono)}.\[\&_code\]\:text-\[8px\] code{font-size:8px}.\[\&_code\]\:text-\[9px\] code{font-size:9px}.\[\&_code\]\:\[overflow-wrap\:anywhere\] code{overflow-wrap:anywhere}.\[\&_code\]\:text-ellipsis code{text-overflow:ellipsis}.\[\&_code\]\:whitespace-normal code{white-space:normal}.\[\&_code\]\:whitespace-nowrap code{white-space:nowrap}.\[\&_code\]\:text-\[\#36423c\] code{color:#36423c}.\[\&_code\]\:text-muted code{color:var(--color-muted)}.\[\&_code\]\:text-secondary code{color:var(--color-secondary)}.\[\&_h3\]\:mt-0 h3{margin-top:0}.\[\&_h3\]\:mb-\[3px\] h3{margin-bottom:3px}.\[\&_h3\]\:text-\[10px\] h3{font-size:10px}.\[\&_h3\]\:tracking-\[\.08em\] h3{--tw-tracking:.08em;letter-spacing:.08em}.\[\&_h3\]\:text-secondary h3{color:var(--color-secondary)}.\[\&_h3\]\:uppercase h3{text-transform:uppercase}.\[\&_i\]\:opacity-40 i{opacity:.4}.\[\&_p\]\:mt-1 p{margin-top:var(--spacing)}.\[\&_p\]\:mb-0 p{margin-bottom:0}.\[\&_p\]\:text-\[9px\] p{font-size:9px}.\[\&_p\]\:\[overflow-wrap\:anywhere\] p{overflow-wrap:anywhere}.\[\&_p\]\:text-\[\#735b37\] p{color:#735b37}.\[\&_p\]\:text-muted p{color:var(--color-muted)}.\[\&_pre\]\:font-mono pre{font-family:var(--font-mono)}.\[\&_small\]\:mt-\[3px\] small{margin-top:3px}.\[\&_small\]\:block small{display:block}.\[\&_small\]\:overflow-hidden small{overflow:hidden}.\[\&_small\]\:font-mono small{font-family:var(--font-mono)}.\[\&_small\]\:text-\[7px\] small{font-size:7px}.\[\&_small\]\:text-\[8px\] small{font-size:8px}.\[\&_small\]\:text-ellipsis small{text-overflow:ellipsis}.\[\&_small\]\:whitespace-nowrap small{white-space:nowrap}.\[\&_small\]\:text-muted small{color:var(--color-muted)}.\[\&_small\]\:text-secondary small{color:var(--color-secondary)}.\[\&_small\]\:uppercase small{text-transform:uppercase}.\[\&_span\]\:block span{display:block}.\[\&_span\]\:overflow-hidden span{overflow:hidden}.\[\&_span\]\:font-mono span{font-family:var(--font-mono)}.\[\&_span\]\:text-\[8px\] span{font-size:8px}.\[\&_span\]\:text-ellipsis span{text-overflow:ellipsis}.\[\&_span\]\:text-\[\#6d7872\] span{color:#6d7872}.\[\&_span\]\:text-\[\#8b7655\] span{color:#8b7655}.\[\&_span\]\:text-muted span{color:var(--color-muted)}.\[\&_span\]\:text-secondary span{color:var(--color-secondary)}.\[\&_strong\]\:mt-\[5px\] strong{margin-top:5px}.\[\&_strong\]\:block strong{display:block}.\[\&_strong\]\:overflow-hidden strong{overflow:hidden}.\[\&_strong\]\:text-\[10px\] strong{font-size:10px}.\[\&_strong\]\:text-\[11px\] strong{font-size:11px}.\[\&_strong\]\:font-semibold strong{--tw-font-weight:var(--font-weight-semibold);font-weight:var(--font-weight-semibold)}.\[\&_strong\]\:text-ellipsis strong{text-overflow:ellipsis}.\[\&_strong\]\:whitespace-nowrap strong{white-space:nowrap}.\[\&_strong\]\:text-\[\#26322c\] strong{color:#26322c}.\[\&_svg\]\:size-\[11px\] svg{width:11px;height:11px}.\[\&_svg\]\:fill-current svg{fill:currentColor}.\[\&\>\.empty-copy\]\:m-3>.empty-copy,.\[\&\>\.inspector-loading\]\:m-3>.inspector-loading{margin:calc(var(--spacing) * 3)}.\[\&\>\:first-child\]\:mt-0>:first-child{margin-top:0}.\[\&\>\:last-child\]\:mb-0>:last-child{margin-bottom:0}.\[\&\>code\]\:mt-0\.5>code{margin-top:calc(var(--spacing) * .5)}.\[\&\>code\]\:block>code{display:block}.\[\&\>code\]\:min-w-0>code{min-width:0}.\[\&\>code\]\:truncate>code{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\[\&\>code\]\:text-\[7px\]>code{font-size:7px}.\[\&\>code\]\:text-\[8px\]>code{font-size:8px}.\[\&\>code\]\:\[overflow-wrap\:anywhere\]>code{overflow-wrap:anywhere}.\[\&\>code\]\:text-muted>code{color:var(--color-muted)}.\[\&\>div\]\:mt-1\.5>div{margin-top:calc(var(--spacing) * 1.5)}.\[\&\>div\]\:mt-\[9px\]>div{margin-top:9px}.\[\&\>div\]\:mb-\[9px\]>div{margin-bottom:9px}.\[\&\>div\]\:h-\[38px\]>div{height:38px}.\[\&\>div\]\:animate-pulse>div{animation:var(--animate-pulse)}.\[\&\>div\]\:rounded-\[7px\]>div{border-radius:7px}.\[\&\>div\]\:border>div{border-style:var(--tw-border-style);border-width:1px}.\[\&\>div\]\:border-t>div{border-top-style:var(--tw-border-style);border-top-width:1px}.\[\&\>div\]\:border-\[\#ead1a2\]>div{border-color:#ead1a2}.\[\&\>div\]\:border-line>div{border-color:var(--color-line)}.\[\&\>div\]\:bg-\[\#edf1ef\]>div{background-color:#edf1ef}.\[\&\>div\]\:bg-panel>div{background-color:var(--color-panel)}.\[\&\>div\]\:p-2\.5>div{padding:calc(var(--spacing) * 2.5)}.\[\&\>div\]\:pt-2>div{padding-top:calc(var(--spacing) * 2)}.\[\&\>div\]\:\[overflow-wrap\:anywhere\]>div{overflow-wrap:anywhere}.\[\&\>div\:first-child\]\:mb-\[9px\]>div:first-child{margin-bottom:9px}.\[\&\>div\:first-child\]\:flex>div:first-child{display:flex}.\[\&\>div\:first-child\]\:justify-between>div:first-child{justify-content:space-between}.\[\&\>div\>\:last-child\]\:mb-0>div>:last-child{margin-bottom:0}.\[\&\>h2\]\:my-2>h2{margin-block:calc(var(--spacing) * 2)}.\[\&\>h2\]\:text-\[\#27332d\]>h2{color:#27332d}.\[\&\>p\]\:max-w-\[390px\]>p{max-width:390px}.\[\&\>p\]\:text-xs>p{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.\[\&\>pre\]\:m-0>pre{margin:0}.\[\&\>pre\]\:min-w-0>pre{min-width:0}.\[\&\>pre\]\:\[overflow-wrap\:anywhere\]>pre{overflow-wrap:anywhere}.\[\&\>pre\]\:whitespace-pre-wrap>pre{white-space:pre-wrap}.\[\&\>pre\]\:text-\[\#27332d\]>pre{color:#27332d}.\[\&\>section\]\:mb-\[23px\]>section{margin-bottom:23px}.\[\&\>small\]\:mb-1\.5>small{margin-bottom:calc(var(--spacing) * 1.5)}.\[\&\>small\]\:block>small{display:block}.\[\&\>small\]\:w-full>small{width:100%}.\[\&\>small\]\:font-mono>small{font-family:var(--font-mono)}.\[\&\>small\]\:text-\[7px\]>small{font-size:7px}.\[\&\>small\]\:text-\[8px\]>small{font-size:8px}.\[\&\>small\]\:tracking-\[\.08em\]>small{--tw-tracking:.08em;letter-spacing:.08em}.\[\&\>small\]\:text-muted>small{color:var(--color-muted)}.\[\&\>small\]\:uppercase>small{text-transform:uppercase}.\[\&\>span\]\:mb-\[3px\]>span{margin-bottom:3px}.\[\&\>span\]\:ml-1\.5>span{margin-left:calc(var(--spacing) * 1.5)}.\[\&\>span\]\:block>span{display:block}.\[\&\>span\]\:inline-flex>span{display:inline-flex}.\[\&\>span\]\:size-\[7px\]>span{width:7px;height:7px}.\[\&\>span\]\:gap-\[5px\]>span{gap:5px}.\[\&\>span\]\:rounded-\[5px\]>span{border-radius:5px}.\[\&\>span\]\:rounded-full>span{border-radius:3.40282e38px}.\[\&\>span\]\:border>span{border-style:var(--tw-border-style);border-width:1px}.\[\&\>span\]\:border-line>span{border-color:var(--color-line)}.\[\&\>span\]\:bg-amber>span{background-color:var(--color-amber)}.\[\&\>span\]\:bg-mint>span{background-color:var(--color-mint)}.\[\&\>span\]\:bg-panel>span{background-color:var(--color-panel)}.\[\&\>span\]\:px-1\.5>span{padding-inline:calc(var(--spacing) * 1.5)}.\[\&\>span\]\:py-1>span{padding-block:var(--spacing)}.\[\&\>span\]\:font-mono>span{font-family:var(--font-mono)}.\[\&\>span\]\:text-xs>span{font-size:var(--text-xs);line-height:var(--tw-leading,var(--text-xs--line-height))}.\[\&\>span\]\:text-\[8px\]>span{font-size:8px}.\[\&\>span\]\:text-\[9px\]>span{font-size:9px}.\[\&\>span\]\:text-\[40px\]>span{font-size:40px}.\[\&\>span\]\:leading-none>span{--tw-leading:1;line-height:1}.\[\&\>span\]\:text-acid>span{color:var(--color-acid)}.\[\&\>span\]\:text-amber>span{color:var(--color-amber)}.\[\&\>span\]\:text-muted>span{color:var(--color-muted)}.\[\&\>span\]\:uppercase>span{text-transform:uppercase}.\[\&\>span\:first-child\]\:w-2\.5>span:first-child{width:calc(var(--spacing) * 2.5)}.\[\&\>span\:first-child\]\:text-acid>span:first-child{color:var(--color-acid)}.\[\&\>strong\]\:block>strong{display:block}.\[\&\>strong\]\:inline>strong{display:inline}.\[\&\>strong\]\:truncate>strong{text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.\[\&\>strong\]\:text-\[10px\]>strong{font-size:10px}.\[\&\>strong\]\:tracking-\[\.08em\]>strong{--tw-tracking:.08em;letter-spacing:.08em}.\[\&\>strong\]\:uppercase>strong{text-transform:uppercase}.\[\&\>summary\]\:cursor-pointer>summary{cursor:pointer}.\[\&\>summary\]\:text-amber>summary{color:var(--color-amber)}.\[\&\>time\]\:whitespace-nowrap>time{white-space:nowrap}.\[\&\>time\]\:text-muted>time{color:var(--color-muted)}}@keyframes gradientRotate{0%{background-position:100% 100%}50%{background-position:50% 100%}to{background-position:100% 100%}}.gradient-animate{transition:background .5s;animation:10s infinite gradientRotate;background:linear-gradient(var(--color-panel),var(--color-panel)) padding-box,linear-gradient(315deg,#7affd9,#4249ff 68%,#7affd9) border-box!important;background-size:100% 100%,200% 200%!important;border-color:#0000!important}@media(prefers-reduced-motion:reduce){.gradient-animate{animation:none}}@property --tw-translate-x{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-y{syntax:"*";inherits:false;initial-value:0}@property --tw-translate-z{syntax:"*";inherits:false;initial-value:0}@property --tw-rotate-x{syntax:"*";inherits:false}@property --tw-rotate-y{syntax:"*";inherits:false}@property --tw-rotate-z{syntax:"*";inherits:false}@property --tw-skew-x{syntax:"*";inherits:false}@property --tw-skew-y{syntax:"*";inherits:false}@property --tw-border-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-leading{syntax:"*";inherits:false}@property --tw-font-weight{syntax:"*";inherits:false}@property --tw-tracking{syntax:"*";inherits:false}@property --tw-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-shadow-color{syntax:"*";inherits:false}@property --tw-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-inset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-shadow-color{syntax:"*";inherits:false}@property --tw-inset-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-ring-color{syntax:"*";inherits:false}@property --tw-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-inset-ring-color{syntax:"*";inherits:false}@property --tw-inset-ring-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-ring-inset{syntax:"*";inherits:false}@property --tw-ring-offset-width{syntax:"";inherits:false;initial-value:0}@property --tw-ring-offset-color{syntax:"*";inherits:false;initial-value:#fff}@property --tw-ring-offset-shadow{syntax:"*";inherits:false;initial-value:0 0 #0000}@property --tw-outline-style{syntax:"*";inherits:false;initial-value:solid}@property --tw-blur{syntax:"*";inherits:false}@property --tw-brightness{syntax:"*";inherits:false}@property --tw-contrast{syntax:"*";inherits:false}@property --tw-grayscale{syntax:"*";inherits:false}@property --tw-hue-rotate{syntax:"*";inherits:false}@property --tw-invert{syntax:"*";inherits:false}@property --tw-opacity{syntax:"*";inherits:false}@property --tw-saturate{syntax:"*";inherits:false}@property --tw-sepia{syntax:"*";inherits:false}@property --tw-drop-shadow{syntax:"*";inherits:false}@property --tw-drop-shadow-color{syntax:"*";inherits:false}@property --tw-drop-shadow-alpha{syntax:"";inherits:false;initial-value:100%}@property --tw-drop-shadow-size{syntax:"*";inherits:false}@property --tw-duration{syntax:"*";inherits:false}@property --tw-ease{syntax:"*";inherits:false}@property --tw-content{syntax:"*";inherits:false;initial-value:""}@keyframes pulse{50%{opacity:.5}}.react-flow{direction:ltr;--xy-edge-stroke-default: #b1b1b7;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #555;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(255, 255, 255, .5);--xy-minimap-background-color-default: #fff;--xy-minimap-mask-background-color-default: rgba(240, 240, 240, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #e2e2e2;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: transparent;--xy-background-pattern-dots-color-default: #91919a;--xy-background-pattern-lines-color-default: #eee;--xy-background-pattern-cross-color-default: #e2e2e2;background-color:var(--xy-background-color, var(--xy-background-color-default));--xy-node-color-default: inherit;--xy-node-border-default: 1px solid #1a192b;--xy-node-background-color-default: #fff;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(0, 0, 0, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #1a192b;--xy-node-border-radius-default: 3px;--xy-handle-background-color-default: #1a192b;--xy-handle-border-color-default: #fff;--xy-selection-background-color-default: rgba(0, 89, 220, .08);--xy-selection-border-default: 1px dotted rgba(0, 89, 220, .8);--xy-controls-button-background-color-default: #fefefe;--xy-controls-button-background-color-hover-default: #f4f4f4;--xy-controls-button-color-default: inherit;--xy-controls-button-color-hover-default: inherit;--xy-controls-button-border-color-default: #eee;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #ffffff;--xy-edge-label-color-default: inherit;--xy-resize-background-color-default: #3367d9}.react-flow.dark{--xy-edge-stroke-default: #3e3e3e;--xy-edge-stroke-width-default: 1;--xy-edge-stroke-selected-default: #727272;--xy-connectionline-stroke-default: #b1b1b7;--xy-connectionline-stroke-width-default: 1;--xy-attribution-background-color-default: rgba(150, 150, 150, .25);--xy-minimap-background-color-default: #141414;--xy-minimap-mask-background-color-default: rgba(60, 60, 60, .6);--xy-minimap-mask-stroke-color-default: transparent;--xy-minimap-mask-stroke-width-default: 1;--xy-minimap-node-background-color-default: #2b2b2b;--xy-minimap-node-stroke-color-default: transparent;--xy-minimap-node-stroke-width-default: 2;--xy-background-color-default: #141414;--xy-background-pattern-dots-color-default: #555;--xy-background-pattern-lines-color-default: #333;--xy-background-pattern-cross-color-default: #333;--xy-node-color-default: #f8f8f8;--xy-node-border-default: 1px solid #3c3c3c;--xy-node-background-color-default: #1e1e1e;--xy-node-group-background-color-default: rgba(240, 240, 240, .25);--xy-node-boxshadow-hover-default: 0 1px 4px 1px rgba(255, 255, 255, .08);--xy-node-boxshadow-selected-default: 0 0 0 .5px #999;--xy-handle-background-color-default: #bebebe;--xy-handle-border-color-default: #1e1e1e;--xy-selection-background-color-default: rgba(200, 200, 220, .08);--xy-selection-border-default: 1px dotted rgba(200, 200, 220, .8);--xy-controls-button-background-color-default: #2b2b2b;--xy-controls-button-background-color-hover-default: #3e3e3e;--xy-controls-button-color-default: #f8f8f8;--xy-controls-button-color-hover-default: #fff;--xy-controls-button-border-color-default: #5b5b5b;--xy-controls-box-shadow-default: 0 0 2px 1px rgba(0, 0, 0, .08);--xy-edge-label-background-color-default: #141414;--xy-edge-label-color-default: #f8f8f8}.react-flow__background{background-color:var(--xy-background-color-props, var(--xy-background-color, var(--xy-background-color-default)));pointer-events:none;z-index:-1}.react-flow__container{position:absolute;width:100%;height:100%;top:0;left:0}.react-flow__pane{z-index:1;touch-action:none}.react-flow__pane.draggable{cursor:grab}.react-flow__pane.dragging{cursor:grabbing}.react-flow__pane.selection{cursor:pointer}.react-flow__viewport{transform-origin:0 0;z-index:2;pointer-events:none}.react-flow__renderer{z-index:4}.react-flow__selection{z-index:6}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible{outline:none}.react-flow__edge-path{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default));stroke-width:var(--xy-edge-stroke-width, var(--xy-edge-stroke-width-default));fill:none}.react-flow__connection-path{stroke:var(--xy-connectionline-stroke, var(--xy-connectionline-stroke-default));stroke-width:var(--xy-connectionline-stroke-width, var(--xy-connectionline-stroke-width-default));fill:none}.react-flow .react-flow__edges{position:absolute}.react-flow .react-flow__edges svg{overflow:visible;position:absolute;pointer-events:none}.react-flow__edge{pointer-events:visibleStroke}.react-flow__edge.selectable{cursor:pointer}.react-flow__edge.animated path{stroke-dasharray:5;animation:dashdraw .5s linear infinite}.react-flow__edge.animated path.react-flow__edge-interaction{stroke-dasharray:none;animation:none}.react-flow__edge.inactive{pointer-events:none}.react-flow__edge.selected,.react-flow__edge:focus,.react-flow__edge:focus-visible{outline:none}.react-flow__edge.selected .react-flow__edge-path,.react-flow__edge.selectable:focus .react-flow__edge-path,.react-flow__edge.selectable:focus-visible .react-flow__edge-path{stroke:var(--xy-edge-stroke-selected, var(--xy-edge-stroke-selected-default))}.react-flow__edge-textwrapper{pointer-events:all}.react-flow__edge .react-flow__edge-text{pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__arrowhead polyline{stroke:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__arrowhead polyline.arrowclosed{fill:var(--xy-edge-stroke, var(--xy-edge-stroke-default))}.react-flow__connection{pointer-events:none}.react-flow__connection .animated{stroke-dasharray:5;animation:dashdraw .5s linear infinite}svg.react-flow__connectionline{z-index:1001;overflow:visible;position:absolute}.react-flow__nodes{pointer-events:none;transform-origin:0 0}.react-flow__node{position:absolute;-webkit-user-select:none;-moz-user-select:none;user-select:none;pointer-events:all;transform-origin:0 0;box-sizing:border-box;cursor:default}.react-flow__node.selectable{cursor:pointer}.react-flow__node.draggable{cursor:grab;pointer-events:all}.react-flow__node.draggable.dragging{cursor:grabbing}.react-flow__nodesselection{z-index:3;transform-origin:left top;pointer-events:none}.react-flow__nodesselection-rect{position:absolute;pointer-events:all;cursor:grab}.react-flow__handle{position:absolute;pointer-events:none;min-width:5px;min-height:5px;width:6px;height:6px;background-color:var(--xy-handle-background-color, var(--xy-handle-background-color-default));border:1px solid var(--xy-handle-border-color, var(--xy-handle-border-color-default));border-radius:100%}.react-flow__handle.connectingfrom{pointer-events:all}.react-flow__handle.connectionindicator{pointer-events:all;cursor:crosshair}.react-flow__handle-bottom{top:auto;left:50%;bottom:0;transform:translate(-50%,50%)}.react-flow__handle-top{top:0;left:50%;transform:translate(-50%,-50%)}.react-flow__handle-left{top:50%;left:0;transform:translate(-50%,-50%)}.react-flow__handle-right{top:50%;right:0;transform:translate(50%,-50%)}.react-flow__edgeupdater{cursor:move;pointer-events:all}.react-flow__pane.selection .react-flow__panel{pointer-events:none}.react-flow__panel{position:absolute;z-index:5;margin:15px}.react-flow__panel.top{top:0}.react-flow__panel.bottom{bottom:0}.react-flow__panel.top.center,.react-flow__panel.bottom.center{left:50%;transform:translate(-15px) translate(-50%)}.react-flow__panel.left{left:0}.react-flow__panel.right{right:0}.react-flow__panel.left.center,.react-flow__panel.right.center{top:50%;transform:translateY(-15px) translateY(-50%)}.react-flow__attribution{font-size:10px;background:var(--xy-attribution-background-color, var(--xy-attribution-background-color-default));padding:2px 3px;margin:0}.react-flow__attribution a{text-decoration:none;color:#999}@keyframes dashdraw{0%{stroke-dashoffset:10}}.react-flow__edgelabel-renderer{position:absolute;width:100%;height:100%;pointer-events:none;-webkit-user-select:none;-moz-user-select:none;user-select:none;left:0;top:0}.react-flow__viewport-portal{position:absolute;width:100%;height:100%;left:0;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__minimap{background:var( --xy-minimap-background-color-props, var(--xy-minimap-background-color, var(--xy-minimap-background-color-default)) )}.react-flow__minimap-svg{display:block}.react-flow__minimap-mask{fill:var( --xy-minimap-mask-background-color-props, var(--xy-minimap-mask-background-color, var(--xy-minimap-mask-background-color-default)) );stroke:var( --xy-minimap-mask-stroke-color-props, var(--xy-minimap-mask-stroke-color, var(--xy-minimap-mask-stroke-color-default)) );stroke-width:var( --xy-minimap-mask-stroke-width-props, var(--xy-minimap-mask-stroke-width, var(--xy-minimap-mask-stroke-width-default)) )}.react-flow__minimap-node{fill:var( --xy-minimap-node-background-color-props, var(--xy-minimap-node-background-color, var(--xy-minimap-node-background-color-default)) );stroke:var( --xy-minimap-node-stroke-color-props, var(--xy-minimap-node-stroke-color, var(--xy-minimap-node-stroke-color-default)) );stroke-width:var( --xy-minimap-node-stroke-width-props, var(--xy-minimap-node-stroke-width, var(--xy-minimap-node-stroke-width-default)) )}.react-flow__background-pattern.dots{fill:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-dots-color-default)) )}.react-flow__background-pattern.lines{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-lines-color-default)) )}.react-flow__background-pattern.cross{stroke:var( --xy-background-pattern-color-props, var(--xy-background-pattern-color, var(--xy-background-pattern-cross-color-default)) )}.react-flow__controls{display:flex;flex-direction:column;box-shadow:var(--xy-controls-box-shadow, var(--xy-controls-box-shadow-default))}.react-flow__controls.horizontal{flex-direction:row}.react-flow__controls-button{display:flex;justify-content:center;align-items:center;height:26px;width:26px;padding:4px;border:none;background:var(--xy-controls-button-background-color, var(--xy-controls-button-background-color-default));border-bottom:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) );color:var( --xy-controls-button-color-props, var(--xy-controls-button-color, var(--xy-controls-button-color-default)) );cursor:pointer;-webkit-user-select:none;-moz-user-select:none;user-select:none}.react-flow__controls-button svg{width:100%;max-width:12px;max-height:12px;fill:currentColor}.react-flow__edge.updating .react-flow__edge-path{stroke:#777}.react-flow__edge-text{font-size:10px}.react-flow__node.selectable:focus,.react-flow__node.selectable:focus-visible{outline:none}.react-flow__node-input,.react-flow__node-default,.react-flow__node-output,.react-flow__node-group{padding:10px;border-radius:var(--xy-node-border-radius, var(--xy-node-border-radius-default));width:150px;font-size:12px;color:var(--xy-node-color, var(--xy-node-color-default));text-align:center;border:var(--xy-node-border, var(--xy-node-border-default));background-color:var(--xy-node-background-color, var(--xy-node-background-color-default))}.react-flow__node-input.selectable:hover,.react-flow__node-default.selectable:hover,.react-flow__node-output.selectable:hover,.react-flow__node-group.selectable:hover{box-shadow:var(--xy-node-boxshadow-hover, var(--xy-node-boxshadow-hover-default))}.react-flow__node-input.selectable.selected,.react-flow__node-input.selectable:focus,.react-flow__node-input.selectable:focus-visible,.react-flow__node-default.selectable.selected,.react-flow__node-default.selectable:focus,.react-flow__node-default.selectable:focus-visible,.react-flow__node-output.selectable.selected,.react-flow__node-output.selectable:focus,.react-flow__node-output.selectable:focus-visible,.react-flow__node-group.selectable.selected,.react-flow__node-group.selectable:focus,.react-flow__node-group.selectable:focus-visible{box-shadow:var(--xy-node-boxshadow-selected, var(--xy-node-boxshadow-selected-default))}.react-flow__node-group{background-color:var(--xy-node-group-background-color, var(--xy-node-group-background-color-default))}.react-flow__nodesselection-rect,.react-flow__selection{background:var(--xy-selection-background-color, var(--xy-selection-background-color-default));border:var(--xy-selection-border, var(--xy-selection-border-default))}.react-flow__nodesselection-rect:focus,.react-flow__nodesselection-rect:focus-visible,.react-flow__selection:focus,.react-flow__selection:focus-visible{outline:none}.react-flow__controls-button:hover{background:var( --xy-controls-button-background-color-hover-props, var(--xy-controls-button-background-color-hover, var(--xy-controls-button-background-color-hover-default)) );color:var( --xy-controls-button-color-hover-props, var(--xy-controls-button-color-hover, var(--xy-controls-button-color-hover-default)) )}.react-flow__controls-button:disabled{pointer-events:none}.react-flow__controls-button:disabled svg{fill-opacity:.4}.react-flow__controls-button:last-child{border-bottom:none}.react-flow__controls.horizontal .react-flow__controls-button{border-bottom:none;border-right:1px solid var( --xy-controls-button-border-color-props, var(--xy-controls-button-border-color, var(--xy-controls-button-border-color-default)) )}.react-flow__controls.horizontal .react-flow__controls-button:last-child{border-right:none}.react-flow__resize-control{position:absolute}.react-flow__resize-control.left,.react-flow__resize-control.right{cursor:ew-resize}.react-flow__resize-control.top,.react-flow__resize-control.bottom{cursor:ns-resize}.react-flow__resize-control.top.left,.react-flow__resize-control.bottom.right{cursor:nwse-resize}.react-flow__resize-control.bottom.left,.react-flow__resize-control.top.right{cursor:nesw-resize}.react-flow__resize-control.handle{width:5px;height:5px;border:1px solid #fff;border-radius:1px;background-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));translate:-50% -50%}.react-flow__resize-control.handle.left{left:0;top:50%}.react-flow__resize-control.handle.right{left:100%;top:50%}.react-flow__resize-control.handle.top{left:50%;top:0}.react-flow__resize-control.handle.bottom{left:50%;top:100%}.react-flow__resize-control.handle.top.left,.react-flow__resize-control.handle.bottom.left{left:0}.react-flow__resize-control.handle.top.right,.react-flow__resize-control.handle.bottom.right{left:100%}.react-flow__resize-control.line{border-color:var(--xy-resize-background-color, var(--xy-resize-background-color-default));border-width:0;border-style:solid}.react-flow__resize-control.line.left,.react-flow__resize-control.line.right{width:1px;transform:translate(-50%);top:0;height:100%}.react-flow__resize-control.line.left{left:0;border-left-width:1px}.react-flow__resize-control.line.right{left:100%;border-right-width:1px}.react-flow__resize-control.line.top,.react-flow__resize-control.line.bottom{height:1px;transform:translateY(-50%);left:0;width:100%}.react-flow__resize-control.line.top{top:0;border-top-width:1px}.react-flow__resize-control.line.bottom{border-bottom-width:1px;top:100%}.react-flow__edge-textbg{fill:var(--xy-edge-label-background-color, var(--xy-edge-label-background-color-default))}.react-flow__edge-text{fill:var(--xy-edge-label-color, var(--xy-edge-label-color-default))} diff --git a/src/runtime/operator/web_assets/assets/protobuf-BR9ifi4u.js b/src/runtime/operator/web_assets/assets/protobuf-BR9ifi4u.js new file mode 100644 index 0000000..930ab2a --- /dev/null +++ b/src/runtime/operator/web_assets/assets/protobuf-BR9ifi4u.js @@ -0,0 +1,4 @@ +function ge(r){let e=typeof r;if(e=="object"){if(Array.isArray(r))return"array";if(r===null)return"null"}return e}function Be(r){return r!==null&&typeof r=="object"&&!Array.isArray(r)}let v="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".split(""),Y=[];for(let r=0;r>4,a=s,i=2;break;case 2:t[n++]=(a&15)<<4|(s&60)>>2,a=s,i=3;break;case 3:t[n++]=(a&3)<<6|s,i=0;break}}if(i==1)throw Error("invalid base64 string.");return t.subarray(0,n)}function Ne(r){let e="",t=0,n,i=0;for(let s=0;s>2],i=(n&3)<<4,t=1;break;case 1:e+=v[i|n>>4],i=(n&15)<<2,t=2;break;case 2:e+=v[i|n>>6],e+=v[n&63],t=0;break}return t&&(e+=v[i],e+="=",t==1&&(e+="=")),e}var q;(function(r){r.symbol=Symbol.for("protobuf-ts/unknown"),r.onRead=(t,n,i,s,a)=>{(e(n)?n[r.symbol]:n[r.symbol]=[]).push({no:i,wireType:s,data:a})},r.onWrite=(t,n,i)=>{for(let{no:s,wireType:a,data:o}of r.list(n))i.tag(s,a).raw(o)},r.list=(t,n)=>{if(e(t)){let i=t[r.symbol];return n?i.filter(s=>s.no==n):i}return[]},r.last=(t,n)=>r.list(t,n).slice(-1)[0];const e=t=>t&&Array.isArray(t[r.symbol])})(q||(q={}));function Le(r,e){return Object.assign(Object.assign({},r),e)}var I;(function(r){r[r.Varint=0]="Varint",r[r.Bit64=1]="Bit64",r[r.LengthDelimited=2]="LengthDelimited",r[r.StartGroup=3]="StartGroup",r[r.EndGroup=4]="EndGroup",r[r.Bit32=5]="Bit32"})(I||(I={}));function Fe(){let r=0,e=0;for(let n=0;n<28;n+=7){let i=this.buf[this.pos++];if(r|=(i&127)<>4,(t&128)==0)return this.assertBounds(),[r,e];for(let n=3;n<=31;n+=7){let i=this.buf[this.pos++];if(e|=(i&127)<>>s,o=!(!(a>>>7)&&e==0),f=(o?a|128:a)&255;if(t.push(f),!o)return}const n=r>>>28&15|(e&7)<<4,i=e>>3!=0;if(t.push((i?n|128:n)&255),!!i){for(let s=3;s<31;s=s+7){const a=e>>>s,o=!!(a>>>7),f=(o?a|128:a)&255;if(t.push(f),!o)return}t.push(e>>>31&1)}}const J=65536*65536;function we(r){let e=r[0]=="-";e&&(r=r.slice(1));const t=1e6;let n=0,i=0;function s(a,o){const f=Number(r.slice(a,o));i*=t,n=n*t+f,n>=J&&(i=i+(n/J|0),n=n%J)}return s(-24,-18),s(-18,-12),s(-12,-6),s(-6),[e,n,i]}function Q(r,e){if(e>>>0<=2097151)return""+(J*e+(r>>>0));let t=r&16777215,n=(r>>>24|e<<8)>>>0&16777215,i=e>>16&65535,s=t+n*6777216+i*6710656,a=n+i*8147497,o=i*2,f=1e7;s>=f&&(a+=Math.floor(s/f),s%=f),a>=f&&(o+=Math.floor(a/f),a%=f);function u(c,d){let m=c?String(c):"";return d?"0000000".slice(m.length)+m:m}return u(o,0)+u(a,o)+u(s,1)}function ie(r,e){if(r>=0){for(;r>127;)e.push(r&127|128),r=r>>>7;e.push(r)}else{for(let t=0;t<9;t++)e.push(r&127|128),r=r>>7;e.push(1)}}function Re(){let r=this.buf[this.pos++],e=r&127;if((r&128)==0)return this.assertBounds(),e;if(r=this.buf[this.pos++],e|=(r&127)<<7,(r&128)==0)return this.assertBounds(),e;if(r=this.buf[this.pos++],e|=(r&127)<<14,(r&128)==0)return this.assertBounds(),e;if(r=this.buf[this.pos++],e|=(r&127)<<21,(r&128)==0)return this.assertBounds(),e;r=this.buf[this.pos++],e|=(r&15)<<28;for(let t=5;(r&128)!==0&&t<10;t++)r=this.buf[this.pos++];if((r&128)!=0)throw new Error("invalid varint");return this.assertBounds(),e>>>0}let w;function _e(){const r=new DataView(new ArrayBuffer(8));w=globalThis.BigInt!==void 0&&typeof r.getBigInt64=="function"&&typeof r.getBigUint64=="function"&&typeof r.setBigInt64=="function"&&typeof r.setBigUint64=="function"?{MIN:BigInt("-9223372036854775808"),MAX:BigInt("9223372036854775807"),UMIN:BigInt("0"),UMAX:BigInt("18446744073709551615"),C:BigInt,V:r}:void 0}_e();function Ee(r){if(!r)throw new Error("BigInt unavailable, see https://github.com/timostamm/protobuf-ts/blob/v1.0.8/MANUAL.md#bigint-support")}const Ie=/^-?[0-9]+$/,W=4294967296,X=2147483648;class ye{constructor(e,t){this.lo=e|0,this.hi=t|0}isZero(){return this.lo==0&&this.hi==0}toNumber(){let e=this.hi*W+(this.lo>>>0);if(!Number.isSafeInteger(e))throw new Error("cannot convert to safe number");return e}}class D extends ye{static from(e){if(w)switch(typeof e){case"string":if(e=="0")return this.ZERO;if(e=="")throw new Error("string is no integer");e=w.C(e);case"number":if(e===0)return this.ZERO;e=w.C(e);case"bigint":if(!e)return this.ZERO;if(ew.UMAX)throw new Error("ulong too large");return w.V.setBigUint64(0,e,!0),new D(w.V.getInt32(0,!0),w.V.getInt32(4,!0))}else switch(typeof e){case"string":if(e=="0")return this.ZERO;if(e=e.trim(),!Ie.test(e))throw new Error("string is no integer");let[t,n,i]=we(e);if(t)throw new Error("signed value for ulong");return new D(n,i);case"number":if(e==0)return this.ZERO;if(!Number.isSafeInteger(e))throw new Error("number is no integer");if(e<0)throw new Error("signed value for ulong");return new D(e,e/W)}throw new Error("unknown value "+typeof e)}toString(){return w?this.toBigInt().toString():Q(this.lo,this.hi)}toBigInt(){return Ee(w),w.V.setInt32(0,this.lo,!0),w.V.setInt32(4,this.hi,!0),w.V.getBigUint64(0,!0)}}D.ZERO=new D(0,0);class y extends ye{static from(e){if(w)switch(typeof e){case"string":if(e=="0")return this.ZERO;if(e=="")throw new Error("string is no integer");e=w.C(e);case"number":if(e===0)return this.ZERO;e=w.C(e);case"bigint":if(!e)return this.ZERO;if(ew.MAX)throw new Error("signed long too large");return w.V.setBigInt64(0,e,!0),new y(w.V.getInt32(0,!0),w.V.getInt32(4,!0))}else switch(typeof e){case"string":if(e=="0")return this.ZERO;if(e=e.trim(),!Ie.test(e))throw new Error("string is no integer");let[t,n,i]=we(e);if(t){if(i>X||i==X&&n!=0)throw new Error("signed long too small")}else if(i>=X)throw new Error("signed long too large");let s=new y(n,i);return t?s.negate():s;case"number":if(e==0)return this.ZERO;if(!Number.isSafeInteger(e))throw new Error("number is no integer");return e>0?new y(e,e/W):new y(-e,-e/W).negate()}throw new Error("unknown value "+typeof e)}isNegative(){return(this.hi&X)!==0}negate(){let e=~this.hi,t=this.lo;return t?t=~t+1:e+=1,new y(t,e)}toString(){if(w)return this.toBigInt().toString();if(this.isNegative()){let e=this.negate();return"-"+Q(e.lo,e.hi)}return Q(this.lo,this.hi)}toBigInt(){return Ee(w),w.V.setInt32(0,this.lo,!0),w.V.setInt32(4,this.hi,!0),w.V.getBigInt64(0,!0)}}y.ZERO=new y(0,0);const se={readUnknownField:!0,readerFactory:r=>new Ue(r)};function xe(r){return r?Object.assign(Object.assign({},se),r):se}class Ue{constructor(e,t){this.varint64=Fe,this.uint32=Re,this.buf=e,this.len=e.length,this.pos=0,this.view=new DataView(e.buffer,e.byteOffset,e.byteLength),this.textDecoder=t??new TextDecoder("utf-8",{fatal:!0,ignoreBOM:!0})}tag(){let e=this.uint32(),t=e>>>3,n=e&7;if(t<=0||n<0||n>5)throw new Error("illegal tag: field no "+t+" wire type "+n);return[t,n]}skip(e){let t=this.pos;switch(e){case I.Varint:for(;this.buf[this.pos++]&128;);break;case I.Bit64:this.pos+=4;case I.Bit32:this.pos+=4;break;case I.LengthDelimited:let n=this.uint32();this.pos+=n;break;case I.StartGroup:let i;for(;(i=this.tag()[1])!==I.EndGroup;)this.skip(i);break;default:throw new Error("cant skip wire type "+e)}return this.assertBounds(),this.buf.subarray(t,this.pos)}assertBounds(){if(this.pos>this.len)throw new RangeError("premature EOF")}int32(){return this.uint32()|0}sint32(){let e=this.uint32();return e>>>1^-(e&1)}int64(){return new y(...this.varint64())}uint64(){return new D(...this.varint64())}sint64(){let[e,t]=this.varint64(),n=-(e&1);return e=(e>>>1|(t&1)<<31)^n,t=t>>>1^n,new y(e,t)}bool(){let[e,t]=this.varint64();return e!==0||t!==0}fixed32(){return this.view.getUint32((this.pos+=4)-4,!0)}sfixed32(){return this.view.getInt32((this.pos+=4)-4,!0)}fixed64(){return new D(this.sfixed32(),this.sfixed32())}sfixed64(){return new y(this.sfixed32(),this.sfixed32())}float(){return this.view.getFloat32((this.pos+=4)-4,!0)}double(){return this.view.getFloat64((this.pos+=8)-8,!0)}bytes(){let e=this.uint32(),t=this.pos;return this.pos+=e,this.assertBounds(),this.buf.subarray(t,t+e)}string(){return this.textDecoder.decode(this.bytes())}}function g(r,e){if(!r)throw new Error(e)}function Se(r,e){throw new Error("Unexpected object: "+r)}const Ve=34028234663852886e22,ve=-34028234663852886e22,Me=4294967295,Pe=2147483647,je=-2147483648;function K(r){if(typeof r!="number")throw new Error("invalid int 32: "+typeof r);if(!Number.isInteger(r)||r>Pe||rMe||r<0)throw new Error("invalid uint 32: "+r)}function re(r){if(typeof r!="number")throw new Error("invalid float 32: "+typeof r);if(Number.isFinite(r)&&(r>Ve||rnew Xe};function Ke(r){return r?Object.assign(Object.assign({},ae),r):ae}class Xe{constructor(e){this.stack=[],this.textEncoder=e??new TextEncoder,this.chunks=[],this.buf=[]}finish(){this.chunks.push(new Uint8Array(this.buf));let e=0;for(let i=0;i>>0)}raw(e){return this.buf.length&&(this.chunks.push(new Uint8Array(this.buf)),this.buf=[]),this.chunks.push(e),this}uint32(e){for(Z(e);e>127;)this.buf.push(e&127|128),e=e>>>7;return this.buf.push(e),this}int32(e){return K(e),ie(e,this.buf),this}bool(e){return this.buf.push(e?1:0),this}bytes(e){return this.uint32(e.byteLength),this.raw(e)}string(e){let t=this.textEncoder.encode(e);return this.uint32(t.byteLength),this.raw(t)}float(e){re(e);let t=new Uint8Array(4);return new DataView(t.buffer).setFloat32(0,e,!0),this.raw(t)}double(e){let t=new Uint8Array(8);return new DataView(t.buffer).setFloat64(0,e,!0),this.raw(t)}fixed32(e){Z(e);let t=new Uint8Array(4);return new DataView(t.buffer).setUint32(0,e,!0),this.raw(t)}sfixed32(e){K(e);let t=new Uint8Array(4);return new DataView(t.buffer).setInt32(0,e,!0),this.raw(t)}sint32(e){return K(e),e=(e<<1^e>>31)>>>0,ie(e,this.buf),this}sfixed64(e){let t=new Uint8Array(8),n=new DataView(t.buffer),i=y.from(e);return n.setInt32(0,i.lo,!0),n.setInt32(4,i.hi,!0),this.raw(t)}fixed64(e){let t=new Uint8Array(8),n=new DataView(t.buffer),i=D.from(e);return n.setInt32(0,i.lo,!0),n.setInt32(4,i.hi,!0),this.raw(t)}int64(e){let t=y.from(e);return H(t.lo,t.hi,this.buf),this}sint64(e){let t=y.from(e),n=t.hi>>31,i=t.lo<<1^n,s=(t.hi<<1|t.lo>>>31)^n;return H(i,s,this.buf),this}uint64(e){let t=D.from(e);return H(t.lo,t.hi,this.buf),this}}const oe={emitDefaultValues:!1,enumAsInteger:!1,useProtoFieldName:!1,prettySpaces:0},fe={ignoreUnknownFields:!1};function $e(r){return r?Object.assign(Object.assign({},fe),r):fe}function Ce(r){return r?Object.assign(Object.assign({},oe),r):oe}function Je(r,e){var t,n;let i=Object.assign(Object.assign({},r),e);return i.typeRegistry=[...(t=r?.typeRegistry)!==null&&t!==void 0?t:[],...(n=e?.typeRegistry)!==null&&n!==void 0?n:[]],i}const Te=Symbol.for("protobuf-ts/message-type");function ee(r){let e=!1;const t=[];for(let n=0;n!i.includes(a))||!n&&i.some(a=>!s.known.includes(a)))return!1;if(t<1)return!0;for(const a of s.oneofs){const o=e[a];if(!We(o))return!1;if(o.oneofKind===void 0)continue;const f=this.fields.find(u=>u.localName===o.oneofKind);if(!f||!this.field(o[o.oneofKind],f,n,t))return!1}for(const a of this.fields)if(a.oneof===void 0&&!this.field(e[a.localName],a,n,t))return!1;return!0}field(e,t,n,i){let s=t.repeat;switch(t.kind){case"scalar":return e===void 0?t.opt:s?this.scalars(e,t.T,i,t.L):this.scalar(e,t.T,t.L);case"enum":return e===void 0?t.opt:s?this.scalars(e,l.INT32,i):this.scalar(e,l.INT32);case"message":return e===void 0?!0:s?this.messages(e,t.T(),n,i):this.message(e,t.T(),n,i);case"map":if(typeof e!="object"||e===null)return!1;if(i<2)return!0;if(!this.mapKeys(e,t.K,i))return!1;switch(t.V.kind){case"scalar":return this.scalars(Object.values(e),t.V.T,i,t.V.L);case"enum":return this.scalars(Object.values(e),l.INT32,i);case"message":return this.messages(Object.values(e),t.V.T(),n,i)}break}return!0}message(e,t,n,i){return n?t.isAssignable(e,i):t.is(e,i)}messages(e,t,n,i){if(!Array.isArray(e))return!1;if(i<2)return!0;if(n){for(let s=0;sparseInt(s)),t,n);case l.BOOL:return this.scalars(i.slice(0,n).map(s=>s=="true"?!0:s=="false"?!1:s),t,n);default:return this.scalars(i,t,n,U.STRING)}}}function F(r,e){switch(e){case U.BIGINT:return r.toBigInt();case U.NUMBER:return r.toNumber();default:return r.toString()}}class Ge{constructor(e){this.info=e}prepare(){var e;if(this.fMap===void 0){this.fMap={};const t=(e=this.info.fields)!==null&&e!==void 0?e:[];for(const n of t)this.fMap[n.name]=n,this.fMap[n.jsonName]=n,this.fMap[n.localName]=n}}assert(e,t,n){if(!e){let i=ge(n);throw(i=="number"||i=="boolean")&&(i=n.toString()),new Error(`Cannot parse JSON ${i} for ${this.info.typeName}#${t}`)}}read(e,t,n){this.prepare();const i=[];for(const[s,a]of Object.entries(e)){const o=this.fMap[s];if(!o){if(!n.ignoreUnknownFields)throw new Error(`Found unknown field while reading ${this.info.typeName} from JSON format. JSON key: ${s}`);continue}const f=o.localName;let u;if(o.oneof){if(a===null&&(o.kind!=="enum"||o.T()[0]!=="google.protobuf.NullValue"))continue;if(i.includes(o.oneof))throw new Error(`Multiple members of the oneof group "${o.oneof}" of ${this.info.typeName} are present in JSON.`);i.push(o.oneof),u=t[o.oneof]={oneofKind:f}}else u=t;if(o.kind=="map"){if(a===null)continue;this.assert(Be(a),o.name,a);const c=u[f];for(const[d,m]of Object.entries(a)){this.assert(m!==null,o.name+" map value",null);let E;switch(o.V.kind){case"message":E=o.V.T().internalJsonRead(m,n);break;case"enum":if(E=this.enum(o.V.T(),m,o.name,n.ignoreUnknownFields),E===!1)continue;break;case"scalar":E=this.scalar(m,o.V.T,o.V.L,o.name);break}this.assert(E!==void 0,o.name+" map value",m);let k=d;o.K==l.BOOL&&(k=k=="true"?!0:k=="false"?!1:k),k=this.scalar(k,o.K,U.STRING,o.name).toString(),c[k]=E}}else if(o.repeat){if(a===null)continue;this.assert(Array.isArray(a),o.name,a);const c=u[f];for(const d of a){this.assert(d!==null,o.name,null);let m;switch(o.kind){case"message":m=o.T().internalJsonRead(d,n);break;case"enum":if(m=this.enum(o.T(),d,o.name,n.ignoreUnknownFields),m===!1)continue;break;case"scalar":m=this.scalar(d,o.T,o.L,o.name);break}this.assert(m!==void 0,o.name,a),c.push(m)}}else switch(o.kind){case"message":if(a===null&&o.T().typeName!="google.protobuf.Value"){this.assert(o.oneof===void 0,o.name+" (oneof member)",null);continue}u[f]=o.T().internalJsonRead(a,n,u[f]);break;case"enum":if(a===null)continue;let c=this.enum(o.T(),a,o.name,n.ignoreUnknownFields);if(c===!1)continue;u[f]=c;break;case"scalar":if(a===null)continue;u[f]=this.scalar(a,o.T,o.L,o.name);break}}}enum(e,t,n,i){if(e[0]=="google.protobuf.NullValue"&&g(t===null||t==="NULL_VALUE",`Unable to parse field ${this.info.typeName}#${n}, enum ${e[0]} only accepts null.`),t===null)return 0;switch(typeof t){case"number":return g(Number.isInteger(t),`Unable to parse field ${this.info.typeName}#${n}, enum can only be integral number, got ${t}.`),t;case"string":let s=t;e[2]&&t.substring(0,e[2].length)===e[2]&&(s=t.substring(e[2].length));let a=e[1][s];return typeof a>"u"&&i?!1:(g(typeof a=="number",`Unable to parse field ${this.info.typeName}#${n}, enum ${e[0]} has no value for "${t}".`),a)}g(!1,`Unable to parse field ${this.info.typeName}#${n}, cannot parse enum value from ${typeof t}".`)}scalar(e,t,n,i){let s;try{switch(t){case l.DOUBLE:case l.FLOAT:if(e===null)return 0;if(e==="NaN")return Number.NaN;if(e==="Infinity")return Number.POSITIVE_INFINITY;if(e==="-Infinity")return Number.NEGATIVE_INFINITY;if(e===""){s="empty string";break}if(typeof e=="string"&&e.trim().length!==e.length){s="extra whitespace";break}if(typeof e!="string"&&typeof e!="number")break;let a=Number(e);if(Number.isNaN(a)){s="not a number";break}if(!Number.isFinite(a)){s="too large or small";break}return t==l.FLOAT&&re(a),a;case l.INT32:case l.FIXED32:case l.SFIXED32:case l.SINT32:case l.UINT32:if(e===null)return 0;let o;if(typeof e=="number"?o=e:e===""?s="empty string":typeof e=="string"&&(e.trim().length!==e.length?s="extra whitespace":o=Number(e)),o===void 0)break;return t==l.UINT32?Z(o):K(o),o;case l.INT64:case l.SFIXED64:case l.SINT64:if(e===null)return F(y.ZERO,n);if(typeof e!="number"&&typeof e!="string")break;return F(y.from(e),n);case l.FIXED64:case l.UINT64:if(e===null)return F(D.ZERO,n);if(typeof e!="number"&&typeof e!="string")break;return F(D.from(e),n);case l.BOOL:if(e===null)return!1;if(typeof e!="boolean")break;return e;case l.STRING:if(e===null)return"";if(typeof e!="string"){s="extra whitespace";break}try{encodeURIComponent(e)}catch(f){f="invalid UTF8";break}return e;case l.BYTES:if(e===null||e==="")return new Uint8Array(0);if(typeof e!="string")break;return pe(e)}}catch(a){s=a.message}this.assert(!1,i+(s?" - "+s:""),e)}}class Ye{constructor(e){var t;this.fields=(t=e.fields)!==null&&t!==void 0?t:[]}write(e,t){const n={},i=e;for(const s of this.fields){if(!s.oneof){let u=this.field(s,i[s.localName],t);u!==void 0&&(n[t.useProtoFieldName?s.name:s.jsonName]=u);continue}const a=i[s.oneof];if(a.oneofKind!==s.localName)continue;const o=s.kind=="scalar"||s.kind=="enum"?Object.assign(Object.assign({},t),{emitDefaultValues:!0}):t;let f=this.field(s,a[s.localName],o);g(f!==void 0),n[t.useProtoFieldName?s.name:s.jsonName]=f}return n}field(e,t,n){let i;if(e.kind=="map"){g(typeof t=="object"&&t!==null);const s={};switch(e.V.kind){case"scalar":for(const[f,u]of Object.entries(t)){const c=this.scalar(e.V.T,u,e.name,!1,!0);g(c!==void 0),s[f.toString()]=c}break;case"message":const a=e.V.T();for(const[f,u]of Object.entries(t)){const c=this.message(a,u,e.name,n);g(c!==void 0),s[f.toString()]=c}break;case"enum":const o=e.V.T();for(const[f,u]of Object.entries(t)){g(u===void 0||typeof u=="number");const c=this.enum(o,u,e.name,!1,!0,n.enumAsInteger);g(c!==void 0),s[f.toString()]=c}break}(n.emitDefaultValues||Object.keys(s).length>0)&&(i=s)}else if(e.repeat){g(Array.isArray(t));const s=[];switch(e.kind){case"scalar":for(let f=0;f0||n.emitDefaultValues)&&(i=s)}else switch(e.kind){case"scalar":i=this.scalar(e.T,t,e.name,e.opt,n.emitDefaultValues);break;case"enum":i=this.enum(e.T(),t,e.name,e.opt,n.emitDefaultValues,n.enumAsInteger);break;case"message":i=this.message(e.T(),t,e.name,n);break}return i}enum(e,t,n,i,s,a){if(e[0]=="google.protobuf.NullValue")return!s&&!i?void 0:null;if(t===void 0){g(i);return}if(!(t===0&&!s&&!i))return g(typeof t=="number"),g(Number.isInteger(t)),a||!e[1].hasOwnProperty(t)?t:e[2]?e[2]+e[1][t]:e[1][t]}message(e,t,n,i){return t===void 0?i.emitDefaultValues?null:void 0:e.internalJsonWrite(t,i)}scalar(e,t,n,i,s){if(t===void 0){g(i);return}const a=s||i;switch(e){case l.INT32:case l.SFIXED32:case l.SINT32:return t===0?a?0:void 0:(K(t),t);case l.FIXED32:case l.UINT32:return t===0?a?0:void 0:(Z(t),t);case l.FLOAT:re(t);case l.DOUBLE:return t===0?a?0:void 0:(g(typeof t=="number"),Number.isNaN(t)?"NaN":t===Number.POSITIVE_INFINITY?"Infinity":t===Number.NEGATIVE_INFINITY?"-Infinity":t);case l.STRING:return t===""?a?"":void 0:(g(typeof t=="string"),t);case l.BOOL:return t===!1?a?!1:void 0:(g(typeof t=="boolean"),t);case l.UINT64:case l.FIXED64:g(typeof t=="number"||typeof t=="string"||typeof t=="bigint");let o=D.from(t);return o.isZero()&&!a?void 0:o.toString();case l.INT64:case l.SFIXED64:case l.SINT64:g(typeof t=="number"||typeof t=="string"||typeof t=="bigint");let f=y.from(t);return f.isZero()&&!a?void 0:f.toString();case l.BYTES:return g(t instanceof Uint8Array),t.byteLength?Ne(t):a?"":void 0}}}function te(r,e=U.STRING){switch(r){case l.BOOL:return!1;case l.UINT64:case l.FIXED64:return F(D.ZERO,e);case l.INT64:case l.SFIXED64:case l.SINT64:return F(y.ZERO,e);case l.DOUBLE:case l.FLOAT:return 0;case l.BYTES:return new Uint8Array(0);case l.STRING:return"";default:return 0}}class He{constructor(e){this.info=e}prepare(){var e;if(!this.fieldNoToField){const t=(e=this.info.fields)!==null&&e!==void 0?e:[];this.fieldNoToField=new Map(t.map(n=>[n.no,n]))}}read(e,t,n,i){this.prepare();const s=i===void 0?e.len:e.pos+i;for(;e.post.no-n.no)}}write(e,t,n){this.prepare();for(const s of this.fields){let a,o,f=s.repeat,u=s.localName;if(s.oneof){const c=e[s.oneof];if(c.oneofKind!==u)continue;a=c[u],o=!0}else a=e[u],o=!1;switch(s.kind){case"scalar":case"enum":let c=s.kind=="enum"?l.INT32:s.T;if(f)if(g(Array.isArray(a)),f==G.PACKED)this.packed(t,c,s.no,a);else for(const d of a)this.scalar(t,c,s.no,d,!0);else a===void 0?g(s.opt):this.scalar(t,c,s.no,a,o||s.opt);break;case"message":if(f){g(Array.isArray(a));for(const d of a)this.message(t,n,s.T(),s.no,d)}else this.message(t,n,s.T(),s.no,a);break;case"map":g(typeof a=="object"&&a!==null);for(const[d,m]of Object.entries(a))this.mapEntry(t,n,s,d,m);break}}let i=n.writeUnknownFields;i!==!1&&(i===!0?q.onWrite:i)(this.info.typeName,e,t)}mapEntry(e,t,n,i,s){e.tag(n.no,I.LengthDelimited),e.fork();let a=i;switch(n.K){case l.INT32:case l.FIXED32:case l.UINT32:case l.SFIXED32:case l.SINT32:a=Number.parseInt(i);break;case l.BOOL:g(i=="true"||i=="false"),a=i=="true";break}switch(this.scalar(e,n.K,1,a,!0),n.V.kind){case"scalar":this.scalar(e,n.V.T,2,s,!0);break;case"enum":this.scalar(e,l.INT32,2,s,!0);break;case"message":this.message(e,t,n.V.T(),2,s);break}e.join()}message(e,t,n,i,s){s!==void 0&&(n.internalBinaryWrite(s,e.tag(i,I.LengthDelimited).fork(),t),e.join())}scalar(e,t,n,i,s){let[a,o,f]=this.scalarInfo(t,i);(!f||s)&&(e.tag(n,a),e[o](i))}packed(e,t,n,i){if(!i.length)return;g(t!==l.BYTES&&t!==l.STRING),e.tag(n,I.LengthDelimited),e.fork();let[,s]=this.scalarInfo(t);for(let a=0;ant(i,this)),this.options=n??{}}}class N extends Error{constructor(e,t="UNKNOWN",n){super(e),this.name="RpcError",Object.setPrototypeOf(this,new.target.prototype),this.code=t,this.meta=n??{}}toString(){const e=[this.name+": "+this.message];this.code&&(e.push(""),e.push("Code: "+this.code)),this.serviceName&&this.methodName&&e.push("Method: "+this.serviceName+"/"+this.methodName);let t=Object.entries(this.meta);if(t.length){e.push(""),e.push("Meta:");for(let[n,i]of t)e.push(` ${n}: ${i}`)}return e.join(` +`)}}function rt(r,e){if(!e)return r;let t={};C(r,t),C(e,t);for(let n of Object.keys(e)){let i=e[n];switch(n){case"jsonOptions":t.jsonOptions=Je(r.jsonOptions,t.jsonOptions);break;case"binaryOptions":t.binaryOptions=Le(r.binaryOptions,t.binaryOptions);break;case"meta":t.meta={},C(r.meta,t.meta),C(e.meta,t.meta);break;case"interceptors":t.interceptors=r.interceptors?r.interceptors.concat(i):i.concat();break}}return t}function C(r,e){if(!r)return;let t=e;for(let[n,i]of Object.entries(r))i instanceof Date?t[n]=new Date(i.getTime()):Array.isArray(i)?t[n]=i.concat():t[n]=i}var L;(function(r){r[r.PENDING=0]="PENDING",r[r.REJECTED=1]="REJECTED",r[r.RESOLVED=2]="RESOLVED"})(L||(L={}));class M{constructor(e=!0){this._state=L.PENDING,this._promise=new Promise((t,n)=>{this._resolve=t,this._reject=n}),e&&this._promise.catch(t=>{})}get state(){return this._state}get promise(){return this._promise}resolve(e){if(this.state!==L.PENDING)throw new Error(`cannot resolve ${L[this.state].toLowerCase()}`);this._resolve(e),this._state=L.RESOLVED}reject(e){if(this.state!==L.PENDING)throw new Error(`cannot reject ${L[this.state].toLowerCase()}`);this._reject(e),this._state=L.REJECTED}resolvePending(e){this._state===L.PENDING&&this.resolve(e)}rejectPending(e){this._state===L.PENDING&&this.reject(e)}}class it{constructor(){this._lis={nxt:[],msg:[],err:[],cmp:[]},this._closed=!1,this._itState={q:[]}}onNext(e){return this.addLis(e,this._lis.nxt)}onMessage(e){return this.addLis(e,this._lis.msg)}onError(e){return this.addLis(e,this._lis.err)}onComplete(e){return this.addLis(e,this._lis.cmp)}addLis(e,t){return t.push(e),()=>{let n=t.indexOf(e);n>=0&&t.splice(n,1)}}clearLis(){for(let e of Object.values(this._lis))e.splice(0,e.length)}get closed(){return this._closed!==!1}notifyNext(e,t,n){g((e?1:0)+(t?1:0)+(n?1:0)<=1,"only one emission at a time"),e&&this.notifyMessage(e),t&&this.notifyError(t),n&&this.notifyComplete()}notifyMessage(e){g(!this.closed,"stream is closed"),this.pushIt({value:e,done:!1}),this._lis.msg.forEach(t=>t(e)),this._lis.nxt.forEach(t=>t(e,void 0,!1))}notifyError(e){g(!this.closed,"stream is closed"),this._closed=e,this.pushIt(e),this._lis.err.forEach(t=>t(e)),this._lis.nxt.forEach(t=>t(void 0,e,!1)),this.clearLis()}notifyComplete(){g(!this.closed,"stream is closed"),this._closed=!0,this.pushIt({value:null,done:!0}),this._lis.cmp.forEach(e=>e()),this._lis.nxt.forEach(e=>e(void 0,void 0,!0)),this.clearLis()}[Symbol.asyncIterator](){return this._closed===!0?this.pushIt({value:null,done:!0}):this._closed!==!1&&this.pushIt(this._closed),{next:()=>{let e=this._itState;g(e,"bad state"),g(!e.p,"iterator contract broken");let t=e.q.shift();return t?"value"in t?Promise.resolve(t):Promise.reject(t):(e.p=new M,e.p.promise)}}}pushIt(e){let t=this._itState;if(t.p){const n=t.p;g(n.state==L.PENDING,"iterator contract broken"),"value"in e?n.resolve(e):n.reject(e),delete t.p}else t.q.push(e)}}var st=function(r,e,t,n){function i(s){return s instanceof t?s:new t(function(a){a(s)})}return new(t||(t=Promise))(function(s,a){function o(c){try{u(n.next(c))}catch(d){a(d)}}function f(c){try{u(n.throw(c))}catch(d){a(d)}}function u(c){c.done?s(c.value):i(c.value).then(o,f)}u((n=n.apply(r,e||[])).next())})};class at{constructor(e,t,n,i,s,a,o){this.method=e,this.requestHeaders=t,this.request=n,this.headers=i,this.response=s,this.status=a,this.trailers=o}then(e,t){return this.promiseFinished().then(n=>e?Promise.resolve(e(n)):n,n=>t?Promise.resolve(t(n)):Promise.reject(n))}promiseFinished(){return st(this,void 0,void 0,function*(){let[e,t,n,i]=yield Promise.all([this.headers,this.response,this.status,this.trailers]);return{method:this.method,requestHeaders:this.requestHeaders,request:this.request,headers:e,response:t,status:n,trailers:i}})}}var ot=function(r,e,t,n){function i(s){return s instanceof t?s:new t(function(a){a(s)})}return new(t||(t=Promise))(function(s,a){function o(c){try{u(n.next(c))}catch(d){a(d)}}function f(c){try{u(n.throw(c))}catch(d){a(d)}}function u(c){c.done?s(c.value):i(c.value).then(o,f)}u((n=n.apply(r,e||[])).next())})};class ft{constructor(e,t,n,i,s,a,o){this.method=e,this.requestHeaders=t,this.request=n,this.headers=i,this.responses=s,this.status=a,this.trailers=o}then(e,t){return this.promiseFinished().then(n=>e?Promise.resolve(e(n)):n,n=>t?Promise.resolve(t(n)):Promise.reject(n))}promiseFinished(){return ot(this,void 0,void 0,function*(){let[e,t,n]=yield Promise.all([this.headers,this.status,this.trailers]);return{method:this.method,requestHeaders:this.requestHeaders,request:this.request,headers:e,status:t,trailers:n}})}}function pt(r,e,t,n,i){var s,a,o,f;if(r=="unary"){let u=(c,d,m)=>e.unary(c,d,m);for(const c of((s=n.interceptors)!==null&&s!==void 0?s:[]).filter(d=>d.interceptUnary).reverse()){const d=u;u=(m,E,k)=>c.interceptUnary(d,m,E,k)}return u(t,i,n)}if(r=="serverStreaming"){let u=(c,d,m)=>e.serverStreaming(c,d,m);for(const c of((a=n.interceptors)!==null&&a!==void 0?a:[]).filter(d=>d.interceptServerStreaming).reverse()){const d=u;u=(m,E,k)=>c.interceptServerStreaming(d,m,E,k)}return u(t,i,n)}if(r=="clientStreaming"){let u=(c,d)=>e.clientStreaming(c,d);for(const c of((o=n.interceptors)!==null&&o!==void 0?o:[]).filter(d=>d.interceptClientStreaming).reverse()){const d=u;u=(m,E)=>c.interceptClientStreaming(d,m,E)}return u(t,n)}if(r=="duplex"){let u=(c,d)=>e.duplex(c,d);for(const c of((f=n.interceptors)!==null&&f!==void 0?f:[]).filter(d=>d.interceptDuplex).reverse()){const d=u;u=(m,E)=>c.interceptDuplex(d,m,E)}return u(t,n)}Se(r)}var h;(function(r){r[r.OK=0]="OK",r[r.CANCELLED=1]="CANCELLED",r[r.UNKNOWN=2]="UNKNOWN",r[r.INVALID_ARGUMENT=3]="INVALID_ARGUMENT",r[r.DEADLINE_EXCEEDED=4]="DEADLINE_EXCEEDED",r[r.NOT_FOUND=5]="NOT_FOUND",r[r.ALREADY_EXISTS=6]="ALREADY_EXISTS",r[r.PERMISSION_DENIED=7]="PERMISSION_DENIED",r[r.UNAUTHENTICATED=16]="UNAUTHENTICATED",r[r.RESOURCE_EXHAUSTED=8]="RESOURCE_EXHAUSTED",r[r.FAILED_PRECONDITION=9]="FAILED_PRECONDITION",r[r.ABORTED=10]="ABORTED",r[r.OUT_OF_RANGE=11]="OUT_OF_RANGE",r[r.UNIMPLEMENTED=12]="UNIMPLEMENTED",r[r.INTERNAL=13]="INTERNAL",r[r.UNAVAILABLE=14]="UNAVAILABLE",r[r.DATA_LOSS=15]="DATA_LOSS"})(h||(h={}));var ut=function(r,e,t,n){function i(s){return s instanceof t?s:new t(function(a){a(s)})}return new(t||(t=Promise))(function(s,a){function o(c){try{u(n.next(c))}catch(d){a(d)}}function f(c){try{u(n.throw(c))}catch(d){a(d)}}function u(c){c.done?s(c.value):i(c.value).then(o,f)}u((n=n.apply(r,e||[])).next())})};function ce(r,e,t,n,i){if(n)for(let[s,a]of Object.entries(n))if(typeof a=="string")r.append(s,a);else for(let o of a)r.append(s,o);if(r.set("Content-Type",e==="text"?"application/grpc-web-text":"application/grpc-web+proto"),e=="text"&&r.set("Accept","application/grpc-web-text"),r.set("X-Grpc-Web","1"),typeof t=="number"){if(t<=0)throw new N(`timeout ${t} ms exceeded`,h[h.DEADLINE_EXCEEDED]);r.set("grpc-timeout",`${t}m`)}else if(t){const s=t.getTime(),a=Date.now();if(s<=a)throw new N(`deadline ${t} exceeded`,h[h.DEADLINE_EXCEEDED]);r.set("grpc-timeout",`${s-a}m`)}return r}function he(r,e){let t=new Uint8Array(5+r.length);t[0]=R.DATA;for(let n=r.length,i=4;i>0;i--)t[i]=n%256,n>>>=8;return t.set(r,5),e==="binary"?t:Ne(t)}function ne(r,e,t){if(arguments.length===1){let f=r,u;try{u=f.type}catch{}switch(u){case"error":case"opaque":case"opaqueredirect":throw new N(`fetch response type ${f.type}`,h[h.UNKNOWN])}return ne(dt(f.headers),f.status,f.statusText)}let n=r,i=e>=200&&e<300,s=De(n),[a,o]=Ae(n);return(a===void 0||a===h.OK)&&!i&&(a=mt(e),o=t),[a,o,s]}function de(r){let e=ht(r),[t,n]=Ae(e),i=De(e);return[t??h.OK,n,i]}var R;(function(r){r[r.DATA=0]="DATA",r[r.TRAILER=128]="TRAILER"})(R||(R={}));function me(r,e,t){return ut(this,void 0,void 0,function*(){let n,i="",s=new Uint8Array(0),a=ct(e);if(lt(r)){let o=r.getReader();n={next:()=>o.read()}}else n=r[Symbol.asyncIterator]();for(;;){let o=yield n.next();if(o.value!==void 0){if(a==="text"){for(let u=0;u=5&&s[0]===R.DATA;){let f=0;for(let u=1;u<5;u++)f=(f<<8)+s[u];if(s.length-5>=f)t(R.DATA,s.subarray(5,5+f)),s=s.subarray(5+f);else break}}if(o.done){if(s.length===0)break;if(s[0]!==R.TRAILER||s.length<5)throw new N("premature EOF",h[h.DATA_LOSS]);t(R.TRAILER,s.subarray(5));break}}})}const lt=r=>typeof r.getReader=="function";function be(r,e){let t=new Uint8Array(r.length+e.length);return t.set(r),t.set(e,r.length),t}function ct(r){switch(r){case"application/grpc-web-text":case"application/grpc-web-text+proto":return"text";case"application/grpc-web":case"application/grpc-web+proto":return"binary";case void 0:case null:throw new N("missing response content type",h[h.INTERNAL]);default:throw new N("unexpected response content type: "+r,h[h.INTERNAL])}}function Ae(r){let e,t,n=r["grpc-message"];if(n!==void 0){if(Array.isArray(n))return[h.INTERNAL,"invalid grpc-web message"];t=n}let i=r["grpc-status"];if(i!==void 0){if(Array.isArray(i))return[h.INTERNAL,"invalid grpc-web status"];if(e=parseInt(i,10),h[e]===void 0)return[h.INTERNAL,"invalid grpc-web status"]}return[e,t]}function De(r){let e={};for(let[t,n]of Object.entries(r))switch(t){case"grpc-message":case"grpc-status":case"content-type":break;default:e[t]=n}return e}function ht(r){let e={};for(let t of String.fromCharCode.apply(String,r).trim().split(`\r +`)){if(t=="")continue;let[n,...i]=t.split(":");const s=i.join(":").trim();n=n.trim();let a=e[n];typeof a=="string"?e[n]=[a,s]:Array.isArray(a)?a.push(s):e[n]=s}return e}function dt(r){let e={};return r.forEach((t,n)=>{let i=e[n];typeof i=="string"?e[n]=[i,t]:Array.isArray(i)?i.push(t):e[n]=t}),e}function mt(r){switch(r){case 200:return h.OK;case 400:return h.INVALID_ARGUMENT;case 401:return h.UNAUTHENTICATED;case 403:return h.PERMISSION_DENIED;case 404:return h.NOT_FOUND;case 409:return h.ABORTED;case 412:return h.FAILED_PRECONDITION;case 429:return h.RESOURCE_EXHAUSTED;case 499:return h.CANCELLED;case 500:return h.UNKNOWN;case 501:return h.UNIMPLEMENTED;case 503:return h.UNAVAILABLE;case 504:return h.DEADLINE_EXCEEDED;default:return h.UNKNOWN}}class Nt{constructor(e){this.defaultOptions=e}mergeOptions(e){return rt(this.defaultOptions,e)}makeUrl(e,t){let n=t.baseUrl;return n.endsWith("/")&&(n=n.substring(0,n.length-1)),`${n}/${e.service.typeName}/${e.name}`}clientStreaming(e){const t=new N("Client streaming is not supported by grpc-web",h[h.UNIMPLEMENTED]);throw t.methodName=e.name,t.serviceName=e.service.typeName,t}duplex(e){const t=new N("Duplex streaming is not supported by grpc-web",h[h.UNIMPLEMENTED]);throw t.methodName=e.name,t.serviceName=e.service.typeName,t}serverStreaming(e,t,n){var i,s,a,o,f;let u=n,c=(i=u.format)!==null&&i!==void 0?i:"text",d=(s=u.fetch)!==null&&s!==void 0?s:globalThis.fetch,m=(a=u.fetchInit)!==null&&a!==void 0?a:{},E=this.makeUrl(e,u),k=e.I.toBinary(t,u.binaryOptions),S=new M,A=new it,_=!0,O,P=new M,x,j=new M;return d(E,Object.assign(Object.assign({},m),{method:"POST",headers:ce(new globalThis.Headers,c,u.timeout,u.meta),body:he(k,c),signal:(o=n.abort)!==null&&o!==void 0?o:null})).then(p=>{let[b,T,B]=ne(p);if(S.resolve(B),b!=null&&b!==h.OK)throw new N(T??h[b],h[b],B);return b!=null&&(O={code:h[b],detail:T??h[b]}),p}).then(p=>{if(!p.body)throw new N("missing response body",h[h.INTERNAL]);return me(p.body,p.headers.get("content-type"),(b,T)=>{switch(b){case R.DATA:A.notifyMessage(e.O.fromBinary(T,u.binaryOptions)),_=!1;break;case R.TRAILER:let B,V;[B,V,x]=de(T),O={code:h[B],detail:V??h[B]};break}})}).then(()=>{if(!x&&!_)throw new N("missing trailers",h[h.DATA_LOSS]);if(!O)throw new N("missing status",h[h.INTERNAL]);if(O.code!=="OK")throw new N(O.detail,O.code,x);A.notifyComplete(),P.resolve(O),j.resolve(x||{})}).catch(p=>{let b;p instanceof N?b=p:p instanceof Error&&p.name==="AbortError"?b=new N(p.message,h[h.CANCELLED]):b=new N(p instanceof Error?p.message:""+p,h[h.INTERNAL]),b.methodName=e.name,b.serviceName=e.service.typeName,S.rejectPending(b),A.notifyError(b),P.rejectPending(b),j.rejectPending(b)}),new ft(e,(f=u.meta)!==null&&f!==void 0?f:{},t,S.promise,A,P.promise,j.promise)}unary(e,t,n){var i,s,a,o,f;let u=n,c=(i=u.format)!==null&&i!==void 0?i:"text",d=(s=u.fetch)!==null&&s!==void 0?s:globalThis.fetch,m=(a=u.fetchInit)!==null&&a!==void 0?a:{},E=this.makeUrl(e,u),k=e.I.toBinary(t,u.binaryOptions),S=new M,A,_=new M,O,P=new M,x,j=new M;return d(E,Object.assign(Object.assign({},m),{method:"POST",headers:ce(new globalThis.Headers,c,u.timeout,u.meta),body:he(k,c),signal:(o=n.abort)!==null&&o!==void 0?o:null})).then(p=>{let[b,T,B]=ne(p);if(S.resolve(B),b!=null&&b!==h.OK)throw new N(T??h[b],h[b],B);return b!=null&&(O={code:h[b],detail:T??h[b]}),p}).then(p=>{if(!p.body)throw new N("missing response body",h[h.INTERNAL]);return me(p.body,p.headers.get("content-type"),(b,T)=>{switch(b){case R.DATA:if(A)throw new N("unary call received 2nd message",h[h.DATA_LOSS]);A=e.O.fromBinary(T,u.binaryOptions);break;case R.TRAILER:let B,V;[B,V,x]=de(T),O={code:h[B],detail:V??h[B]};break}})}).then(()=>{if(!x&&A)throw new N("missing trailers",h[h.DATA_LOSS]);if(!O)throw new N("missing status",h[h.INTERNAL]);if(!A&&O.code==="OK")throw new N("expected error status",h[h.DATA_LOSS]);if(!A)throw new N(O.detail,O.code,x);if(_.resolve(A),O.code!=="OK")throw new N(O.detail,O.code,x);P.resolve(O),j.resolve(x||{})}).catch(p=>{let b;p instanceof N?b=p:p instanceof Error&&p.name==="AbortError"?b=new N(p.message,h[h.CANCELLED]):b=new N(p instanceof Error?p.message:""+p,h[h.INTERNAL]),b.methodName=e.name,b.serviceName=e.service.typeName,S.rejectPending(b),_.rejectPending(b),P.rejectPending(b),j.rejectPending(b)}),new at(e,(f=u.meta)!==null&&f!==void 0?f:{},t,S.promise,_.promise,P.promise,j.promise)}}export{Nt as G,bt as M,gt as S,q as U,I as W,z as r,pt as s}; diff --git a/src/runtime/operator/web_assets/index.html b/src/runtime/operator/web_assets/index.html new file mode 100644 index 0000000..9f4e57c --- /dev/null +++ b/src/runtime/operator/web_assets/index.html @@ -0,0 +1,20 @@ + + + + + + + + Avalanche Operator + + + + + + + + +
+ + + \ No newline at end of file diff --git a/src/runtime/operator/webhooks.py b/src/runtime/operator/webhooks.py index 9954edb..4efddf0 100644 --- a/src/runtime/operator/webhooks.py +++ b/src/runtime/operator/webhooks.py @@ -74,9 +74,9 @@ def url_for(self, path: str) -> str | None: def reconcile(self, routes: dict[str, WebhookRoute]) -> None: with self._lock: - self._routes = dict(routes) if routes and self._server is None: self._start_locked() + self._routes = dict(routes) def close(self) -> None: with self._lock: diff --git a/src/tui/app.py b/src/tui/app.py index 3e5ee5d..4281647 100644 --- a/src/tui/app.py +++ b/src/tui/app.py @@ -161,6 +161,7 @@ def on_mount(self) -> None: self.push_screen(self._screen) self.store.provider.on_run_update(self._on_run_update_bg) + self.store.provider.on_catalog_update(self.store.enqueue_catalog_update) self.store.provider.on_detail_update(self.store.enqueue_detail_update) self.store.provider.on_log(lambda _: None) self.store.provider.start_stream() @@ -955,7 +956,7 @@ def can_cancel_selected_run(self) -> bool: run = self.store.current_run return ( run is not None - and run.status in {RunStatus.PENDING, RunStatus.RUNNING} + and run.status in {RunStatus.REQUESTING, RunStatus.PENDING, RunStatus.RUNNING} and run.run_id not in self._cancel_run_requests ) diff --git a/src/tui/mock.py b/src/tui/mock.py index c416780..79aee5d 100644 --- a/src/tui/mock.py +++ b/src/tui/mock.py @@ -10,6 +10,7 @@ from uuid import uuid4 from .models import ( + CatalogSnapshot, DetailUpdate, LogDetailAppended, LogEntry, @@ -562,6 +563,7 @@ def __init__(self, *, include_agent_trace: bool = False) -> None: self._workflows[AGENT_TRACE_WORKFLOW.selector] = AGENT_TRACE_WORKFLOW self._runs: dict[str, RunState] = {} self._run_callbacks: list[Callable[[RunState], None]] = [] + self._catalog_callbacks: list[Callable[[CatalogSnapshot], None]] = [] self._log_callbacks: list[Callable[[LogEntry], None]] = [] self._detail_callbacks: list[Callable[[DetailUpdate], None]] = [] self._stream_reset_callbacks: list[Callable[[StreamResetNotice], None]] = [] @@ -837,9 +839,18 @@ def cancel_run(self, run_id: str) -> None: ns.ended_at = time.monotonic() self._notify_run(run) + def get_catalog(self) -> CatalogSnapshot: + return CatalogSnapshot( + operator_instance_id=self.operator_instance_id, + workflows=tuple(self.list_workflows()), + ) + def on_run_update(self, callback: Callable[[RunState], None]) -> None: self._run_callbacks.append(callback) + def on_catalog_update(self, callback: Callable[[CatalogSnapshot], None]) -> None: + self._catalog_callbacks.append(callback) + def on_log(self, callback: Callable[[LogEntry], None]) -> None: self._log_callbacks.append(callback) @@ -853,15 +864,15 @@ def on_stream_reset(self, callback: Callable[[StreamResetNotice], None]) -> None self._stream_reset_callbacks.append(callback) def load_reset_baseline(self, notice: StreamResetNotice) -> ResetBaseline: - workflows = tuple(self.list_workflows()) + catalog = self.get_catalog() return ResetBaseline( generation=notice.generation, operator_instance_id=self.operator_instance_id, as_of_sequence=0, - workflows=workflows, + catalog=catalog, runs_by_workflow={ workflow.selector: tuple(self.list_runs(workflow.selector)) - for workflow in workflows + for workflow in catalog.workflows }, ) diff --git a/src/tui/models.py b/src/tui/models.py index fe431df..8d6b8b1 100644 --- a/src/tui/models.py +++ b/src/tui/models.py @@ -2,6 +2,7 @@ from avalanche.operator.models import ( AgentEventDetailAppended, + CatalogSnapshot, DetailUpdate, LogDetailAppended, LogEntry, @@ -19,6 +20,7 @@ __all__ = [ "AgentEventDetailAppended", + "CatalogSnapshot", "DetailUpdate", "LogEntry", "LogLevel", diff --git a/src/tui/state.py b/src/tui/state.py index f5e04b6..7af12ee 100644 --- a/src/tui/state.py +++ b/src/tui/state.py @@ -5,6 +5,7 @@ from typing import Any, Callable, Protocol, runtime_checkable from .models import ( + CatalogSnapshot, DetailUpdate, LogEntry, ResetBaseline, @@ -25,6 +26,8 @@ class StateProvider(Protocol): def list_workflows(self) -> list[WorkflowInfo]: ... + def get_catalog(self) -> CatalogSnapshot: ... + def list_runs(self, workflow_selector: str) -> list[RunState]: ... def get_run(self, run_id: str) -> RunState | None: ... @@ -40,6 +43,8 @@ def cancel_run(self, run_id: str) -> None: ... def on_run_update(self, callback: Callable[[RunState], None]) -> None: ... + def on_catalog_update(self, callback: Callable[[CatalogSnapshot], None]) -> None: ... + def on_log(self, callback: Callable[[LogEntry], None]) -> None: ... def on_detail_update(self, callback: Callable[[DetailUpdate], None]) -> None: ... def start_stream(self) -> None: diff --git a/src/tui/ui_store.py b/src/tui/ui_store.py index 96122c0..f695c87 100644 --- a/src/tui/ui_store.py +++ b/src/tui/ui_store.py @@ -16,6 +16,7 @@ from .dag_layout import DagNode, SeqGroup, build_nav_grid, nav_move, workflow_to_layout from .models import ( AgentEventDetailAppended, + CatalogSnapshot, DetailUpdate, LogDetailAppended, LogEntry, @@ -269,6 +270,7 @@ def __init__( self.workflows: list[WorkflowInfo] = ( [] if defer_initial_catalog else provider.list_workflows() ) + self.catalog = CatalogSnapshot(workflows=tuple(self.workflows)) self.current_workflow: WorkflowInfo | None = None self.current_run: RunState | None = None self.run_pinned: bool = False # True = user picked a run; False = follow latest @@ -420,6 +422,7 @@ def run_state_label(self) -> str: if self.current_run is None: return "IDLE" return { + RunStatus.REQUESTING: "REQUESTING", RunStatus.RUNNING: "RUNNING", RunStatus.FAILED: "FAILED", RunStatus.SUCCESS: "DONE", @@ -1283,6 +1286,10 @@ def enqueue_polled_run_update( ("polled_run", (selector, data_revision, context_epoch, run)) ) + def enqueue_catalog_update(self, catalog: CatalogSnapshot) -> None: + """Queue one authoritative catalog replacement for the UI thread.""" + self._background_updates.put(("catalog_replaced", catalog)) + @staticmethod def _reset_baseline_validation_error( notice: StreamResetNotice, @@ -2368,6 +2375,13 @@ def _apply_background_updates(self) -> None: except Exception as exc: self.run_error = f"Live state reset failed: {exc}" continue + if kind == "catalog_replaced": + catalog = payload + if catalog.revision >= self.catalog_revision: + self.catalog = catalog + self.catalog_revision = catalog.revision + self._reconcile_workflows(list(catalog.workflows)) + continue if kind == "catalog": self._catalog_refresh_in_flight = False context_epoch, workflows = payload @@ -2539,12 +2553,14 @@ def _apply_reset_baseline(self, baseline: ResetBaseline) -> None: self.current_run.run_id if self.run_pinned and self.current_run else None ) previous_selectors = {workflow.selector for workflow in self.workflows} - baseline_selectors = {workflow.selector for workflow in baseline.workflows} + baseline_selectors = {workflow.selector for workflow in baseline.catalog.workflows} self._workflow_context_epoch += 1 for selector in previous_selectors | baseline_selectors: self._advance_run_data_revision(selector) - self._reconcile_workflows(list(baseline.workflows)) + self.catalog = baseline.catalog + self.catalog_revision = baseline.catalog.revision + self._reconcile_workflows(list(baseline.catalog.workflows)) # A selection change can schedule a refresh during reconciliation. Invalidate # it too so a pre-baseline response cannot overwrite authoritative state. for selector in previous_selectors | baseline_selectors: diff --git a/src/tui/widgets/run_history.py b/src/tui/widgets/run_history.py index 7b8bd44..a437e28 100644 --- a/src/tui/widgets/run_history.py +++ b/src/tui/widgets/run_history.py @@ -19,6 +19,7 @@ ICE_PURPLE, ICE_STEEL, ICE_TEAL, + ICE_WARN, SPINNER_FRAMES, ) @@ -26,6 +27,7 @@ _HEADER_STYLE = Style(color=ICE_STEEL, bold=True) RUN_STATUS_STYLES: dict[RunStatus, Style] = { + RunStatus.REQUESTING: Style(color=ICE_WARN, bold=True), RunStatus.PENDING: Style(color=ICE_STEEL), RunStatus.RUNNING: Style(color=ICE_BRIGHT, bold=True), RunStatus.SUCCESS: Style(color=ICE_TEAL, bold=True), @@ -34,6 +36,7 @@ } RUN_STATUS_ICONS: dict[RunStatus, str] = { + RunStatus.REQUESTING: "◌", RunStatus.PENDING: "○", RunStatus.RUNNING: "◐", RunStatus.SUCCESS: "✓", diff --git a/src/tui/widgets/sidebar.py b/src/tui/widgets/sidebar.py index 9c5952b..c388e97 100644 --- a/src/tui/widgets/sidebar.py +++ b/src/tui/widgets/sidebar.py @@ -18,6 +18,7 @@ ICE_PURPLE, ICE_STEEL, ICE_TEAL, + ICE_WARN, SPINNER_FRAMES, ) @@ -25,6 +26,7 @@ _CURSOR_BG = Style(bgcolor="#1e3555") _STATUS_ICONS: dict[RunStatus, str] = { + RunStatus.REQUESTING: "◌", RunStatus.PENDING: "○", RunStatus.RUNNING: "◐", RunStatus.SUCCESS: "✓", @@ -33,6 +35,7 @@ } _STATUS_STYLES: dict[RunStatus, Style] = { + RunStatus.REQUESTING: Style(color=ICE_WARN, bold=True), RunStatus.PENDING: Style(color=ICE_STEEL), RunStatus.RUNNING: Style(color=ICE_BRIGHT, bold=True), RunStatus.SUCCESS: Style(color=ICE_TEAL, bold=True), diff --git a/src/tui/widgets/status_bar.py b/src/tui/widgets/status_bar.py index eabb98c..3e5a026 100644 --- a/src/tui/widgets/status_bar.py +++ b/src/tui/widgets/status_bar.py @@ -23,6 +23,7 @@ _SEP_STYLE = Style(color=ICE_STEEL) _STATUS_STYLES: dict[RunStatus, Style] = { + RunStatus.REQUESTING: Style(color=ICE_WARN, bold=True), RunStatus.PENDING: Style(color=ICE_STEEL), RunStatus.RUNNING: Style(color=ICE_BRIGHT, bold=True), RunStatus.SUCCESS: Style(color=ICE_TEAL, bold=True), @@ -31,6 +32,7 @@ } _STATUS_ICONS: dict[RunStatus, str] = { + RunStatus.REQUESTING: "◌", RunStatus.PENDING: "○", RunStatus.SUCCESS: "✓", RunStatus.FAILED: "✗", diff --git a/test/agent/agent_step_test.py b/test/agent/agent_step_test.py index 725d2b2..0194501 100644 --- a/test/agent/agent_step_test.py +++ b/test/agent/agent_step_test.py @@ -397,7 +397,49 @@ def flow(): assert flow().run(executor=LocalExecutor()).result() == "ready for review" assert ava.agent_step is ava.agent.agent_step is ava.agent.step - assert captured["builds"][0]["runtime_kwargs"] == {"lm": "root-lm"} + assert captured["builds"][0]["runtime_kwargs"] == {"lm": "root-lm", "verbose": False} + + def test_agent_step_runtime_kwargs_override_quiet_default(self, monkeypatch): + """An explicit step setting takes precedence over the quiet agent default.""" + captured = install_fake( + monkeypatch, + lambda _inputs: SimpleNamespace( + summary=Summary(headline="about Ada", person_count=1), + note="ready", + ), + ) + + @ava.agent_step(SummarySignature, verbose=True) + async def summarize(person: Person, *, agent: ava.Agent) -> str: + return (await agent(person=person)).note + + @ava.workflow + def flow(): + return summarize(Person(id=1, name="Ada")) + + assert flow().run(executor=LocalExecutor()).result() == "ready" + assert captured["builds"][0]["runtime_kwargs"]["verbose"] is True + + def test_workflow_agent_defaults_override_quiet_default(self, monkeypatch): + """A workflow may opt all of its agent steps into verbose traces.""" + captured = install_fake( + monkeypatch, + lambda _inputs: SimpleNamespace( + summary=Summary(headline="about Ada", person_count=1), + note="ready", + ), + ) + + @ava.agent_step(SummarySignature) + async def summarize(person: Person, *, agent: ava.Agent) -> str: + return (await agent(person=person)).note + + @ava.workflow(agent_defaults={"verbose": True}) + def flow(): + return summarize(Person(id=1, name="Ada")) + + assert flow().run(executor=LocalExecutor()).result() == "ready" + assert captured["builds"][0]["runtime_kwargs"]["verbose"] is True def test_decorator_capabilities_reach_predictor(self, monkeypatch): """Decorator capabilities reach the predictor constructed for the step.""" @@ -575,7 +617,7 @@ async def summarize(person: Person, *, agent: ava.Agent) -> str: ] assert metadata["runtime"]["max_iterations"] == 7 assert metadata["runtime"]["debug"] is True - assert metadata["runtime"]["max_llm_calls"] == 50 + assert metadata["runtime"]["verbose"] is False rendered = json.dumps(metadata) assert "secret" not in rendered assert metadata["models"] == { @@ -874,12 +916,15 @@ def fake_build(signature, *, skills, tools, **runtime_kwargs): ] live = [event for event in observed if event["kind"] == "evidence"] assert [event["sequence"] for event in live] == list(range(1, 10)) - assert live[0]["data"] == {"input_fields": ["person"]} + assert live[0]["data"] == { + "input_fields": ["person"], + "inputs": {"person": {"id": 1, "name": "Ada"}}, + } assert live[3]["data"]["call_id"] == "predict-1" assert "input" not in live[3]["data"] assert "output" not in live[4]["data"] assert "args" not in live[5]["data"] - assert live[7]["data"]["reasoning"] == "Check the evidence before summarizing." + assert live[7]["data"]["step"]["reasoning"] == "Check the evidence before summarizing." assert live[8]["data"] == {"status": "completed", "outputs": {"summary": "done"}} assert "result" not in live[6]["data"] terminal = observed[-1] @@ -1124,3 +1169,31 @@ async def test_agent_exports_exception_trace_before_preserving_wrapped_error(mon assert observed[-1]["kind"] == "trace_finished" assert observed[-1]["trace"]["status"] == "error" + + +def test_agent_value_projection_preserves_nested_predict_rlm_files(): + from predict_rlm import File + + projected = agent_step_module._bounded_agent_value( + { + "source": File(path="/tmp/source.pdf"), + "outputs": [File(path="/tmp/report.xlsx")], + } + ) + + assert projected == { + "source": {"kind": "predict_rlm_file", "path": "/tmp/source.pdf"}, + "outputs": [{"kind": "predict_rlm_file", "path": "/tmp/report.xlsx"}], + } + + +def test_agent_value_projection_marks_unsupported_and_oversized_values_unavailable(): + unsupported = agent_step_module._bounded_agent_value({"value": object()}) + oversized = agent_step_module._bounded_agent_value( + "x" * (agent_step_module._MAX_EVIDENCE_VALUE_BYTES + 1) + ) + + assert unsupported == { + "value": {"kind": "unavailable", "reason": "unsupported value type: object"} + } + assert oversized == {"kind": "unavailable", "reason": "value exceeds byte limit"} diff --git a/test/agent_rlm_logs_test.py b/test/agent_rlm_logs_test.py index 7f55afc..c23872c 100644 --- a/test/agent_rlm_logs_test.py +++ b/test/agent_rlm_logs_test.py @@ -23,6 +23,32 @@ from tui.widgets.log_panel import LogWidget +def test_operator_forwards_info_not_debug_logs() -> None: + class Queue: + def __init__(self) -> None: + self.items: list[dict[str, object]] = [] + + def put(self, item: dict[str, object]) -> None: + self.items.append(item) + + queue = Queue() + handler = _QueueLogHandler(queue) + logger = logging.getLogger("test.operator_capture") + old_level = logger.level + old_propagate = logger.propagate + logger.addHandler(handler) + logger.setLevel(logging.DEBUG) + logger.propagate = False + try: + logger.debug("debug detail") + logger.info("run started") + finally: + logger.removeHandler(handler) + logger.setLevel(old_level) + logger.propagate = old_propagate + + assert [item["message"] for item in queue.items] == ["run started"] + @pytest.mark.parametrize("backend", ["local", "ray"]) def test_verbose_rlm_log_retains_agent_step_node_id(backend: str) -> None: class Queue: diff --git a/test/cli_test.py b/test/cli_test.py index b2cad0c..578f907 100644 --- a/test/cli_test.py +++ b/test/cli_test.py @@ -3,6 +3,7 @@ import hashlib import importlib.util import json +import logging import stat import threading import tomllib @@ -69,11 +70,83 @@ def fake_operator_main(argv): "17777", "--webhook-port", "7434", + "--log-level", + "WARNING", "--ray", ] ] +def test_ava_operator_forwards_case_insensitive_log_level(monkeypatch): + from ava_cli import app + + calls = [] + monkeypatch.setattr(app, "_operator_main", lambda argv: calls.append(argv) or 0) + + assert app.main(["operator", "--flows", "examples", "--log-level", "info"]) == 0 + assert calls[0][-2:] == ["--log-level", "INFO"] + + +def test_runtime_operator_configures_logging_before_serve(monkeypatch): + import runtime.operator as runtime_operator + from runtime.operator import __main__ as operator_main + + lifecycle = [] + monkeypatch.setattr( + operator_main.logging, + "basicConfig", + lambda **kwargs: lifecycle.append(("logging", kwargs)), + ) + monkeypatch.setattr( + runtime_operator, + "serve", + lambda flows, **kwargs: lifecycle.append(("serve", (flows, kwargs))), + ) + + assert operator_main.main(["--flows", "examples", "--log-level", "info"]) == 0 + assert lifecycle[0] == ( + "logging", + { + "level": logging.INFO, + "format": "%(asctime)s %(levelname)s %(name)s: %(message)s", + "force": True, + }, + ) + assert lifecycle[1][0] == "serve" + + +def test_ava_operator_delegates_web_listener_configuration(monkeypatch): + from ava_cli import app + + calls = [] + monkeypatch.setattr(app, "_operator_main", lambda argv: calls.append(argv) or 0) + + assert ( + app.main( + [ + "operator", + "--flows", + "examples", + "--web", + "--web-host", + "0.0.0.0", + "--web-port", + "17778", + "--web-trusted-proxy", + ] + ) + == 0 + ) + assert calls[0][-6:] == [ + "--web", + "--web-host", + "0.0.0.0", + "--web-port", + "17778", + "--web-trusted-proxy", + ] + + def test_ava_operator_rejects_old_workflows_flag(): from ava_cli import app diff --git a/test/operator_example_discovery_test.py b/test/operator_example_discovery_test.py index c25d6b3..907fe72 100644 --- a/test/operator_example_discovery_test.py +++ b/test/operator_example_discovery_test.py @@ -28,7 +28,7 @@ def _free_port() -> int: def test_registry_scan_of_examples_returns_only_canonical_flows(monkeypatch, tmp_path): monkeypatch.setenv("AVALANCHE_EXAMPLE_ROOT", str(tmp_path / "examples")) - registry = WorkflowRegistry() + registry = WorkflowRegistry(discovery_timeout=60.0) registry.scan([str(EXAMPLES_DIR)]) @@ -41,7 +41,12 @@ def test_operator_served_with_examples_exposes_canonical_flows_over_grpc( ): monkeypatch.setenv("AVALANCHE_EXAMPLE_ROOT", str(tmp_path / "examples")) port = _free_port() - operator = Operator([str(EXAMPLES_DIR)], watch=False, schedule=False) + operator = Operator( + [str(EXAMPLES_DIR)], + watch=False, + schedule=False, + discovery_timeout=60.0, + ) server = serve(operator, port=port, block=False) provider = GrpcStateProvider(f"localhost:{port}") diff --git a/test/operator_tests/test_grpc.py b/test/operator_tests/test_grpc.py index 21b5601..7f8b08e 100644 --- a/test/operator_tests/test_grpc.py +++ b/test/operator_tests/test_grpc.py @@ -26,6 +26,7 @@ workflow_info_to_proto, ) from avalanche.operator.models import ( + CatalogSnapshot, NodeSnapshot, NodeState, NodeStatus, @@ -43,6 +44,7 @@ from runtime.operator._grpc import MAX_GRPC_MESSAGE_BYTES from runtime.operator.client import _DetailHydrationRaceError, _run_from_snapshot from runtime.operator.proto import operator_pb2 as pb +from runtime.operator.proto import operator_pb2_grpc as pb_grpc from runtime.operator.results import ( MAX_ATTACHMENT_MEDIA_TYPE_LENGTH, MAX_ATTACHMENT_NAME_LENGTH, @@ -80,20 +82,19 @@ def _wait_for_run_success(client, run_id): def test_start_run_wire_preserves_surviving_field_numbers(): request = pb.StartRunRequest( - flow_name="input_workflow", run_id="run_01KCVST2FP4QC5NKZNN5NS0Z2W", workflow_selector="flows/input.py::input_workflow", ) assert request.run_id == "run_01KCVST2FP4QC5NKZNN5NS0Z2W" assert request.workflow_selector == "flows/input.py::input_workflow" - assert pb.StartRunRequest.FLOW_NAME_FIELD_NUMBER == 1 assert pb.StartRunRequest.INPUT_JSON_FIELD_NUMBER == 2 assert pb.StartRunRequest.CONTEXT_JSON_FIELD_NUMBER == 3 assert pb.StartRunRequest.INPUT_FILES_FIELD_NUMBER == 4 assert pb.StartRunRequest.RUN_ID_FIELD_NUMBER == 6 assert pb.StartRunRequest.WORKFLOW_SELECTOR_FIELD_NUMBER == 7 - assert set(pb.StartRunRequest.DESCRIPTOR.fields_by_number) == {1, 2, 3, 4, 6, 7} + assert set(pb.StartRunRequest.DESCRIPTOR.fields_by_number) == {2, 3, 4, 6, 7} + assert "flow_name" not in pb.StartRunRequest.DESCRIPTOR.fields_by_name assert "S3FileReference" not in pb.DESCRIPTOR.message_types_by_name proto_source = Path(pb.__file__).with_name("operator.proto").read_text() @@ -117,6 +118,83 @@ def test_result_file_wire_preserves_empty_metadata_presence(): assert empty.media_type == "" +def test_latest_run_snapshot_client_returns_typed_snapshot_without_mutating_baseline(): + latest = RunSnapshot( + operator_instance_id="operator-1", + as_of_sequence=8, + summary=RunSummary( + run_id="run-selected", + flow_name="flow", + workflow_id="flow", + workflow_display_name="flow", + status=RunStatus.RUNNING, + created_sequence=2, + revision=8, + ), + ) + + class LatestSnapshotStub: + def __init__(self): + self.request = None + + def GetLatestRunSnapshot(self, request, **kwargs): # noqa: N802 + self.request = request + return run_snapshot_to_proto(latest) + + provider = GrpcStateProvider("localhost:1") + stub = LatestSnapshotStub() + provider._stub = stub + retained = RunState( + run_id="run-retained", + flow_name="flow", + operator_instance_id="operator-1", + ) + provider._install_structural_baseline("operator-1", 4, {retained.run_id: retained}) + try: + snapshot = provider.get_latest_run_snapshot("run-selected", "operator-1") + finally: + provider.close() + + assert isinstance(snapshot, RunSnapshot) + assert snapshot == latest + assert stub.request.run_id == "run-selected" + assert stub.request.operator_instance_id == "operator-1" + assert provider._cursor.operator_instance_id == "operator-1" + assert provider._cursor.sequence == 4 + assert set(provider._runs_by_id) == {"run-retained"} + + +def test_latest_run_snapshot_client_preserves_operator_epoch_failure(): + class EpochFailure(grpc.RpcError): + def code(self): + return grpc.StatusCode.FAILED_PRECONDITION + + def details(self): + return "operator instance changed" + + class RestartedStub: + def __init__(self): + self.request = None + + def GetLatestRunSnapshot(self, request, **kwargs): # noqa: N802 + self.request = request + raise EpochFailure() + + provider = GrpcStateProvider("localhost:1") + stub = RestartedStub() + provider._stub = stub + try: + with pytest.raises(OperatorCallError) as error: + provider.get_latest_run_snapshot("run-selected", "operator-old") + finally: + provider.close() + + assert error.value.status is grpc.StatusCode.FAILED_PRECONDITION + assert error.value.details == "operator instance changed" + assert stub.request.run_id == "run-selected" + assert stub.request.operator_instance_id == "operator-old" + + def test_grpc_envelope_includes_bounded_worst_case_metadata_headroom(): worst_case_metadata_bytes = MAX_RESULT_ATTACHMENTS * ( 4 * MAX_ATTACHMENT_NAME_LENGTH + 4 * MAX_ATTACHMENT_MEDIA_TYPE_LENGTH + 256 @@ -210,6 +288,27 @@ def test_start_run_and_complete(self, client): run = client.get_run(run_id) assert run.status == RunStatus.SUCCESS + def test_rapid_starts_publish_requesting_runs_before_preparation( + self, client, grpc_server, monkeypatch + ): + operator, _, _ = grpc_server + release_preparation = threading.Event() + await_prepared = operator._await_prepared + + def delay_preparation(handle): + assert release_preparation.wait(timeout=5) + return await_prepared(handle) + + monkeypatch.setattr(operator, "_await_prepared", delay_preparation) + try: + first_run_id = client.start_run("simple_workflow") + second_run_id = client.start_run("simple_workflow") + + assert client.get_run(first_run_id).status is RunStatus.REQUESTING + assert client.get_run(second_run_id).status is RunStatus.REQUESTING + finally: + release_preparation.set() + def test_start_run_honors_client_run_id(self, client): requested_run_id = "run_client_owned" @@ -270,7 +369,7 @@ def lineage_context_workflow(): run_id = "run_grpc_real" response = provider._stub.StartRun( pb.StartRunRequest( - flow_name="lineage_context_workflow", + workflow_selector="lineage_context_workflow", run_id=run_id, context_json=json.dumps( { @@ -307,7 +406,7 @@ def lineage_context_workflow(): def test_start_run_rejects_bad_file_metadata_before_response(self, client): start_request = pb.StartRunRequest( - flow_name="input_workflow", + workflow_selector="input_workflow", run_id="run_bad_inline_checksum", input_files=[ pb.FileAttachment( @@ -422,10 +521,9 @@ def test_cancel_run(self, client): time.sleep(0.2) # Let it start client.cancel_run(run_id) - # Cancellation is a request; the coordinator publishes the terminal - # state after cooperative completion or the configured forced grace. + # Cancellation may already be terminal by the time this read completes. run = client.get_run(run_id) - assert run.status == RunStatus.RUNNING + assert run.status in {RunStatus.REQUESTING, RunStatus.RUNNING, RunStatus.CANCELLED} deadline = time.monotonic() + 7.0 while time.monotonic() < deadline: run = client.get_run(run_id) @@ -446,24 +544,38 @@ def on_update(run): updates.append((run.run_id, run.status)) client.on_run_update(on_update) + + def recover_stream(notice): + baseline = client.load_reset_baseline(notice) + client.acknowledge_stream_reset( + baseline.generation, + baseline.operator_instance_id, + baseline.as_of_sequence, + ) + + client.on_stream_reset(recover_stream) client.start_stream() - time.sleep(0.2) # Let stream connect + deadline = time.monotonic() + 15 + while time.monotonic() < deadline and client.stream_state is not StreamState.LIVE: + time.sleep(0.05) + assert client.stream_state is StreamState.LIVE run_id = client.start_run("simple_workflow") + completion_deadline = time.monotonic() + 20 - deadline = time.monotonic() + 5 - while time.monotonic() < deadline: - if any(rid == run_id and s == RunStatus.SUCCESS for rid, s in updates): + while time.monotonic() < completion_deadline: + if any(rid == run_id and s == RunStatus.RUNNING for rid, s in updates): break time.sleep(0.05) - # Should have received at least one update with the run completing statuses = [s for rid, s in updates if rid == run_id] - assert len(statuses) > 0, "No stream updates received" - assert RunStatus.SUCCESS in statuses + assert RunStatus.REQUESTING in statuses + assert RunStatus.RUNNING in statuses - def test_legacy_flow_name_request_still_starts(self, client): - response = client._stub.StartRun(pb.StartRunRequest(flow_name="simple_workflow")) + def test_workflow_selector_request_starts(self, client): + response = client._stub.StartRun( + pb.StartRunRequest(workflow_selector="simple_workflow") + ) assert response.run_id.startswith("run_") @@ -512,11 +624,11 @@ def details(self): return "stream offline" class SplitHealthStub: - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 raise Unavailable() - def ListFlows(self, request, **kwargs): # noqa: N802 - return pb.FlowList() + def GetCatalog(self, request, **kwargs): # noqa: N802 + return pb.CatalogSnapshotMsg() provider._stub = SplitHealthStub() try: @@ -560,7 +672,7 @@ def details(self): return "operation failed" class ErrorStub: - def ListFlows(self, request, **kwargs): # noqa: N802 + def GetCatalog(self, request, **kwargs): # noqa: N802 raise RpcFailure() provider._stub = ErrorStub() @@ -626,7 +738,7 @@ def ReadTrace(self, request, **kwargs): # noqa: N802 try: detail = provider.hydrate_trace("run-trace-health", "agent") assert detail is not None - assert detail.trace_body == {"complete": True} + assert detail.trace_body == {"complete": True, "steps": []} assert provider.operator_reachable is True assert provider.stream_state is StreamState.FAILED assert provider.stream_error == "UNAVAILABLE: live updates interrupted" @@ -689,7 +801,7 @@ def ReadTrace(self, request, **kwargs): # noqa: N802 for run_id in runs: detail = provider.hydrate_trace(run_id, "agent") assert detail is not None - assert detail.trace_body == {} + assert detail.trace_body == {"steps": []} assert provider._retained_detail_count <= 2 assert provider._retained_detail_bytes <= 4 assert len(provider._detail_cache_usage) <= 2 @@ -818,6 +930,9 @@ def GetRunSnapshot(self, request, **kwargs): # noqa: N802 ) def ListLogs(self, request, **kwargs): # noqa: N802 + assert request.before_sequence == 0 + assert request.node_id == "" + assert request.order == pb.DESCRIPTOR_PAGE_ORDER_FORWARD sequence = request.after_sequence + 1 return pb.LogPage( operator_instance_id="operator-1", @@ -836,6 +951,8 @@ def ListLogs(self, request, **kwargs): # noqa: N802 ) def ListAgentEvents(self, request, **kwargs): # noqa: N802 + assert request.before_event_sequence == 0 + assert request.order == pb.DESCRIPTOR_PAGE_ORDER_FORWARD sequence = request.after_event_sequence + 1 return pb.AgentEventPage( operator_instance_id="operator-1", @@ -996,12 +1113,12 @@ def details(self): return "late application error" class BlockingStub: - def ListFlows(self, request, **kwargs): # noqa: N802 + def GetCatalog(self, request, **kwargs): # noqa: N802 entered.set() assert release.wait(timeout=1.0) if status is not None: raise RpcFailure() - return pb.FlowList() + return pb.CatalogSnapshotMsg() def invoke() -> None: try: @@ -1055,7 +1172,7 @@ def __next__(self): raise StopIteration class IdleStub: - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 return IdleStream() provider._stub = IdleStub() @@ -1133,7 +1250,7 @@ def __iter__(self): raise Unavailable() class FailingStub: - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 return AcceptedThenUnavailable() provider._stream_stop = RecordingStop() @@ -1174,9 +1291,9 @@ def wait(self, delay): self.stopped = True return self.stopped - duplicate = pb.RunUpdateEnvelope( + duplicate = pb.OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=7, run_created=pb.RunCreated( summary=pb.RunSummaryMsg( @@ -1199,7 +1316,7 @@ def __iter__(self): raise Unavailable() class DuplicateStub: - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 requests.append((request.operator_instance_id, request.after_sequence)) return DuplicateThenUnavailable() @@ -1248,9 +1365,9 @@ def initial_metadata(self): return () def __iter__(self): - yield pb.RunUpdateEnvelope( + yield pb.OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=1, run_created=pb.RunCreated( summary=pb.RunSummaryMsg( @@ -1269,7 +1386,7 @@ class ProgressStub: def __init__(self): self.calls = 0 - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 self.calls += 1 if self.calls == 1: raise Unavailable() @@ -1315,7 +1432,7 @@ class ReconnectingStub: def __init__(self): self.calls = 0 - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 self.calls += 1 observed.append(provider.stream_state) if self.calls == 1: @@ -1328,9 +1445,9 @@ def initial_metadata(self): def __iter__(self): observed.append(provider.stream_state) - yield pb.RunUpdateEnvelope( + yield pb.OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=1, run_created=pb.RunCreated( summary=pb.RunSummaryMsg( @@ -1542,9 +1659,13 @@ def ListRunSummaries(self, request, **kwargs): # noqa: N802 runs=[run_summary_to_proto(summaries[1])], ) - def ListFlows(self, request, **kwargs): # noqa: N802 + def GetCatalog(self, request, **kwargs): # noqa: N802 self.list_flows_calls += 1 - return pb.FlowList(flows=[workflow_info_to_proto(workflow)]) + return pb.CatalogSnapshotMsg( + operator_instance_id="operator-new", + as_of_sequence=3, + workflows=[workflow_info_to_proto(workflow)], + ) def GetRunSnapshot(self, request, **kwargs): # noqa: N802 self.snapshot_calls.append(request.run_id) @@ -1571,7 +1692,7 @@ def GetRunSnapshot(self, request, **kwargs): # noqa: N802 assert baseline.generation == 7 assert baseline.operator_instance_id == "operator-new" assert baseline.as_of_sequence == 3 - assert [item.selector for item in baseline.workflows] == [workflow.selector] + assert [item.selector for item in baseline.catalog.workflows] == [workflow.selector] assert [run.run_id for run in baseline.runs_by_workflow[workflow.selector]] == [ "run_1", "run_2", @@ -1615,8 +1736,12 @@ def __init__(self): self.summary_calls = 0 self.snapshot_requests = [] - def ListFlows(self, request, **kwargs): # noqa: N802 - return pb.FlowList(flows=[workflow_info_to_proto(workflow)]) + def GetCatalog(self, request, **kwargs): # noqa: N802 + return pb.CatalogSnapshotMsg( + operator_instance_id="operator-live", + as_of_sequence=self.current_sequence, + workflows=[workflow_info_to_proto(workflow)], + ) def ListRunSummaries(self, request, **kwargs): # noqa: N802 self.summary_calls += 1 @@ -1662,7 +1787,7 @@ def load_baseline(notice): generation=notice.generation, operator_instance_id="operator-restarted", as_of_sequence=3, - workflows=(), + catalog=CatalogSnapshot(workflows=()), runs_by_workflow={}, ) @@ -1676,9 +1801,9 @@ def load_baseline(notice): release = threading.Event() received = [] - reset_envelope = pb.RunUpdateEnvelope( + reset_envelope = pb.OperatorUpdateEnvelope( operator_instance_id="operator-restarted", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=2, run_created=pb.RunCreated( summary=pb.RunSummaryMsg( @@ -1697,9 +1822,9 @@ def initial_metadata(self): return () def __iter__(self): - yield pb.RunUpdateEnvelope( + yield pb.OperatorUpdateEnvelope( operator_instance_id="operator-restarted", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=4, run_created=pb.RunCreated( summary=pb.RunSummaryMsg( @@ -1719,7 +1844,7 @@ class RestartedStub: def __init__(self): self.calls = 0 - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 self.calls += 1 assert metadata is None if self.calls == 1: @@ -1797,7 +1922,7 @@ def test_reset_acknowledgement_requires_exact_validated_baseline( generation=notice.generation, operator_instance_id="operator-restarted", as_of_sequence=3, - workflows=(), + catalog=CatalogSnapshot(workflows=()), runs_by_workflow={}, ) provider = GrpcStateProvider( @@ -1848,13 +1973,13 @@ def test_update_epoch_change_requires_reset_at_equal_or_higher_sequence( reset_observed = threading.Event() class RestartedStub: - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 assert request.operator_instance_id == "operator-original" assert request.after_sequence == 99 assert metadata is None - yield pb.RunUpdateEnvelope( + yield pb.OperatorUpdateEnvelope( operator_instance_id="operator-restarted", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=observed_sequence, run_created=pb.RunCreated( summary=pb.RunSummaryMsg( @@ -1898,14 +2023,14 @@ def test_client_skips_duplicate_update_sequence_without_epoch_reset(): received = [] class DuplicateFirstStub: - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 assert request.operator_instance_id == "operator-1" assert request.after_sequence == 99 assert metadata is None for sequence, run_id in ((99, "duplicate"), (100, "run_live")): - yield pb.RunUpdateEnvelope( + yield pb.OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=sequence, run_created=pb.RunCreated( summary=pb.RunSummaryMsg( @@ -1944,7 +2069,7 @@ def __init__(self): self.calls = 0 self.thread_ids = set() - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 self.calls += 1 self.thread_ids.add(threading.get_ident()) @@ -2003,7 +2128,7 @@ def __init__(self): self.calls = 0 self.post_close_calls = 0 - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 self.calls += 1 if close_returned.is_set(): self.post_close_calls += 1 @@ -2053,7 +2178,7 @@ class FailingStub: def __init__(self): self.calls = 0 - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 self.calls += 1 called.set() raise Unavailable() @@ -2078,7 +2203,7 @@ def StreamRunUpdates(self, request, *, metadata): # noqa: N802 assert provider.stream_state is StreamState.STOPPED -def test_canonical_client_requests_include_cached_legacy_name(): +def test_canonical_client_requests_use_workflow_selector(): canonical_id = "root/reports/daily.py::build_report" class CapturingStub: @@ -2086,9 +2211,9 @@ def __init__(self): self.start_request = None self.list_request = None - def ListFlows(self, request, **kwargs): # noqa: N802 - return pb.FlowList( - flows=[ + def GetCatalog(self, request, **kwargs): # noqa: N802 + return pb.CatalogSnapshotMsg( + workflows=[ pb.FlowInfoMsg( name="Daily report", display_name="Daily report", @@ -2115,7 +2240,6 @@ def ListRunSummaries(self, request, **kwargs): # noqa: N802 assert provider.start_run(canonical_id) == "run_legacy" assert stub.start_request.workflow_selector == canonical_id - assert stub.start_request.flow_name == "Daily report" assert provider.list_runs(canonical_id) == [] assert stub.list_request.workflow_selector == canonical_id @@ -2133,9 +2257,9 @@ def _capture(self, name, timeout): assert timeout is not None assert 0 < timeout < float("inf") - def ListFlows(self, request, *, timeout, **kwargs): # noqa: N802 + def GetCatalog(self, request, *, timeout, **kwargs): # noqa: N802 self._capture("list", timeout) - return pb.FlowList() + return pb.CatalogSnapshotMsg() def StartRun(self, request, *, timeout, **kwargs): # noqa: N802 self._capture("start", timeout) @@ -2153,6 +2277,18 @@ def GetRunSnapshot(self, request, *, timeout, **kwargs): # noqa: N802 ), ) + def GetLatestRunSnapshot(self, request, *, timeout, **kwargs): # noqa: N802 + self._capture("latest", timeout) + return pb.RunSnapshotMsg( + operator_instance_id=request.operator_instance_id, + as_of_sequence=2, + summary=pb.RunSummaryMsg( + run_id=request.run_id, + flow_name="flow", + status="running", + ), + ) + def ListRunSummaries(self, request, *, timeout, **kwargs): # noqa: N802 self._capture("cursor" if request.page_size == 1 else "runs", timeout) return pb.RunSummaryPage( @@ -2170,6 +2306,7 @@ def CancelRun(self, request, *, timeout, **kwargs): # noqa: N802 provider.list_workflows() provider.start_run("flow") provider.get_run("run_1") + provider.get_latest_run_snapshot("run_1", "operator-1") provider.list_runs("flow") provider.cancel_run("run_1") finally: @@ -2180,6 +2317,7 @@ def CancelRun(self, request, *, timeout, **kwargs): # noqa: N802 ("start", 3.5), ("cursor", 3.5), ("get", 3.5), + ("latest", 3.5), ("runs", 3.5), ("cancel", 3.5), ] @@ -2241,10 +2379,17 @@ def test_canonical_and_ambiguous_grpc_selection(tmp_path): assert error.value.status is grpc.StatusCode.INVALID_ARGUMENT (roots[0] / "flow.py").write_text("VALUE = 1\n") - with pytest.raises(OperatorCallError) as error: - provider.start_run(ids[0]) - assert error.value.status is grpc.StatusCode.FAILED_PRECONDITION - assert "preparation failed" in str(error.value).lower() + failed_run_id = provider.start_run(ids[0]) + failed_run = None + deadline = time.monotonic() + 15 + while time.monotonic() < deadline: + failed_run = provider.get_run(failed_run_id) + if failed_run is not None and failed_run.status == RunStatus.FAILED: + break + time.sleep(0.05) + assert failed_run is not None + assert failed_run.status == RunStatus.FAILED + assert any("preparation failed" in item.message.lower() for item in failed_run.logs) finally: provider.close() server.stop(grace=1) @@ -2459,6 +2604,152 @@ def _seed_hydration_run(operator, run_id: str) -> RunState: return run +def test_grpc_latest_snapshot_and_newest_pages_preserve_status_contract(): + operator = Operator([], watch=False, schedule=False) + server = None + channel = None + try: + run = _seed_hydration_run(operator, "run-latest-page") + baseline = operator.list_run_summaries(page_size=10) + retained = operator.get_run_snapshot( + run.run_id, + operator_instance_id=baseline.operator_instance_id, + as_of_sequence=baseline.as_of_sequence, + ) + assert retained is not None + operator._apply_event( + run.run_id, + _event_handle(), + {"type": "running", "timestamp": 1.0}, + ) + + port = _unused_port() + server = serve(operator, port=port, block=False) + channel = grpc.insecure_channel(f"localhost:{port}") + grpc.channel_ready_future(channel).result(timeout=5) + stub = pb_grpc.OperatorServiceStub(channel) + + latest = stub.GetLatestRunSnapshot( + pb.GetLatestRunSnapshotRequest( + run_id=run.run_id, + operator_instance_id=operator.operator_instance_id, + ) + ) + exact = stub.GetRunSnapshot( + pb.GetRunSnapshotRequest( + run_id=run.run_id, + operator_instance_id=baseline.operator_instance_id, + as_of_sequence=baseline.as_of_sequence, + ) + ) + assert latest.as_of_sequence > exact.as_of_sequence + assert latest.summary.status == RunStatus.RUNNING.value + assert exact.summary.status == retained.summary.status.value + + class CountingLogs(list): + def __init__(self, entries): + super().__init__(entries) + self.item_reads = 0 + + def __getitem__(self, index): + if isinstance(index, int): + self.item_reads += 1 + return super().__getitem__(index) + + with operator._lock: + counted_logs = CountingLogs(operator._logs[run.run_id]) + operator._logs[run.run_id] = counted_logs + + first_logs = stub.ListLogs( + pb.ListLogsRequest( + page_token=latest.log_page_token, + page_size=2, + node_id="agent-1", + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + ) + assert [item.sequence for item in first_logs.logs] == sorted( + (item.sequence for item in first_logs.logs), + reverse=True, + ) + assert first_logs.next_page_token + second_logs = stub.ListLogs( + pb.ListLogsRequest( + page_token=first_logs.next_page_token, + page_size=2, + before_sequence=first_logs.logs[-1].sequence, + node_id="agent-1", + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + ) + assert { + item.sequence for item in first_logs.logs + }.isdisjoint(item.sequence for item in second_logs.logs) + reads_before_missing_page = counted_logs.item_reads + missing_logs = stub.ListLogs( + pb.ListLogsRequest( + page_token=latest.log_page_token, + page_size=2, + node_id="missing-agent", + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + ) + assert list(missing_logs.logs) == [] + assert counted_logs.item_reads == reads_before_missing_page + + first_events = stub.ListAgentEvents( + pb.ListAgentEventsRequest( + page_token=latest.nodes[0].event_page_token, + page_size=2, + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + ) + assert [item.event_sequence for item in first_events.events] == sorted( + (item.event_sequence for item in first_events.events), + reverse=True, + ) + + with pytest.raises(grpc.RpcError) as cursor_error: + stub.ListLogs( + pb.ListLogsRequest( + page_token=first_logs.next_page_token, + page_size=2, + before_sequence=first_logs.logs[-1].sequence - 1, + node_id="agent-1", + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + ) + assert cursor_error.value.code() is grpc.StatusCode.INVALID_ARGUMENT + + with pytest.raises(grpc.RpcError) as stale_error: + stub.GetLatestRunSnapshot( + pb.GetLatestRunSnapshotRequest( + run_id=run.run_id, + operator_instance_id="stale-operator", + ) + ) + assert stale_error.value.code() is grpc.StatusCode.FAILED_PRECONDITION + + with pytest.raises(grpc.RpcError) as missing_error: + stub.GetLatestRunSnapshot( + pb.GetLatestRunSnapshotRequest( + run_id="missing-run", + operator_instance_id=operator.operator_instance_id, + ) + ) + assert missing_error.value.code() is grpc.StatusCode.NOT_FOUND + + with pytest.raises(grpc.RpcError) as token_error: + stub.ListLogs(pb.ListLogsRequest(page_token="not-a-token")) + assert token_error.value.code() is grpc.StatusCode.INVALID_ARGUMENT + finally: + if channel is not None: + channel.close() + if server is not None: + server.stop(grace=0).wait() + operator.close() + + def test_grpc_lazily_hydrates_paged_details_and_chunked_trace( monkeypatch, ): @@ -2487,10 +2778,15 @@ def __getattr__(self, name): return getattr(delegate, name) def ListLogs(self, request, **kwargs): # noqa: N802 + assert request.before_sequence == 0 + assert request.node_id == "" + assert request.order == pb.DESCRIPTOR_PAGE_ORDER_FORWARD self.log_cursors.append(request.after_sequence) return delegate.ListLogs(request, **kwargs) def ListAgentEvents(self, request, **kwargs): # noqa: N802 + assert request.before_event_sequence == 0 + assert request.order == pb.DESCRIPTOR_PAGE_ORDER_FORWARD self.event_cursors.append(request.after_event_sequence) return delegate.ListAgentEvents(request, **kwargs) diff --git a/test/operator_tests/test_grpc_client_auth_tls.py b/test/operator_tests/test_grpc_client_auth_tls.py index 9e28e9f..3759a00 100644 --- a/test/operator_tests/test_grpc_client_auth_tls.py +++ b/test/operator_tests/test_grpc_client_auth_tls.py @@ -91,8 +91,8 @@ def fake_insecure_channel(address: str, *, options): class AuthenticatedOperatorService(pb_grpc.OperatorServiceServicer): - def ListFlows(self, request, context): # noqa: N802 + def GetCatalog(self, request, context): # noqa: N802 authorization = dict(context.invocation_metadata()).get("authorization") if authorization != "Bearer secret": context.abort(grpc.StatusCode.UNAUTHENTICATED, "missing_bearer") - return pb.FlowList(flows=[pb.FlowInfoMsg(name="demo-flow")]) + return pb.CatalogSnapshotMsg(workflows=[pb.FlowInfoMsg(name="demo-flow")]) diff --git a/test/operator_tests/test_operator.py b/test/operator_tests/test_operator.py index 6813ef4..f72d9bb 100644 --- a/test/operator_tests/test_operator.py +++ b/test/operator_tests/test_operator.py @@ -20,6 +20,7 @@ RunState, RunStatus, RunStatusChanged, + WorkflowDiscoveryDiagnostic, ) from avalanche.operator.operator import ( MAX_RUN_ID_BYTES, @@ -27,12 +28,14 @@ RunAlreadyExistsError, ) from avalanche.operator.scheduler import Scheduler +from runtime.operator import operator as operator_module from runtime.operator.run_worker import ( _import_isolated_ray, _QueueStream, _with_local_node_observers, _with_ray_node_observers, ) +from runtime.operator.webhooks import WebhookRoute FIXTURES_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "fixtures") @@ -59,6 +62,42 @@ def test_start_run_returns_run_id(self): op = self._make_operator() run_id = op.start_run("simple_workflow") assert run_id.startswith("run_") + run = op.get_run(run_id) + assert run is not None + assert run.triggered_at is not None + + def test_start_run_publishes_multiple_requesting_runs_before_preparation(self, monkeypatch): + op = self._make_operator() + release_preparation = threading.Event() + await_prepared = op._await_prepared + + def delay_preparation(handle): + assert release_preparation.wait(timeout=5) + return await_prepared(handle) + + monkeypatch.setattr(op, "_await_prepared", delay_preparation) + try: + first_run_id = op.start_run("simple_workflow") + second_run_id = op.start_run("simple_workflow") + + assert op.get_run(first_run_id).status == RunStatus.REQUESTING + assert op.get_run(second_run_id).status == RunStatus.REQUESTING + + release_preparation.set() + deadline = time.monotonic() + 10 + while time.monotonic() < deadline: + statuses = [ + op.get_run(first_run_id).status, + op.get_run(second_run_id).status, + ] + if statuses == [RunStatus.SUCCESS, RunStatus.SUCCESS]: + break + time.sleep(0.05) + + assert statuses == [RunStatus.SUCCESS, RunStatus.SUCCESS] + finally: + release_preparation.set() + op.close() def test_custom_run_id_reservation_rejects_sequential_duplicate(self): op = self._make_operator() @@ -99,7 +138,7 @@ def test_run_completes_successfully(self): run_id = op.start_run("simple_workflow") # Wait for completion - deadline = time.monotonic() + 5 + deadline = time.monotonic() + 10 while time.monotonic() < deadline: run = op.get_run(run_id) if run and run.status in (RunStatus.SUCCESS, RunStatus.FAILED): @@ -196,7 +235,33 @@ def test_list_runs_filters_by_workflow(self): runs = op.list_runs("nonexistent") assert len(runs) == 0 - def test_refresh_invalid_file_removes_descriptor_and_schedule(self, tmp_path): + def test_refresh_unchanged_catalog_does_not_publish_update(self, tmp_path, caplog): + workflow_file = tmp_path / "flow.py" + workflow_file.write_text( + "import avalanche as ava\n" + "@ava.workflow\n" + "def unchanged():\n" + " return None\n" + ) + operator = Operator( + workflow_paths=[str(workflow_file)], + schedule=False, + watch=False, + ) + try: + initial = operator.get_catalog() + + caplog.set_level("INFO", logger="runtime.operator.operator") + operator._refresh_workflows() + + current = operator.get_catalog() + assert current.revision == initial.revision + assert current.as_of_sequence == initial.as_of_sequence + assert "Workflow reload unchanged" in caplog.text + finally: + operator.close() + + def test_refresh_invalid_file_retains_descriptor_and_schedule(self, tmp_path, caplog): workflow_file = tmp_path / "scheduled.py" workflow_file.write_text( "import avalanche as ava\n" @@ -211,10 +276,88 @@ def test_refresh_invalid_file_removes_descriptor_and_schedule(self, tmp_path): assert len(operator._scheduler.list_schedules()) == 1 workflow_file.write_text("invalid Python !!!\n") + caplog.set_level("INFO", logger="runtime.operator.operator") operator._refresh_workflows() - assert operator.list_workflows() == [] - assert operator._scheduler.list_schedules() == [] + assert [item.workflow_id for item in operator.list_workflows()] == [ + "scheduled.py::scheduled" + ] + assert len(operator._scheduler.list_schedules()) == 1 + assert [item.kind for item in operator.list_diagnostics()] == ["import_error"] + assert "Workflow reload failed; retaining catalog revision" in caplog.text + assert "import_error" in caplog.text + + def test_reload_diagnostic_summary_bounds_complete_rendered_text(self): + diagnostic = WorkflowDiscoveryDiagnostic( + path="/" + ("nested/" * 1_000), + kind="invalid_catalog", + message="invalid catalog", + ) + + summary = operator_module._summarize_reload_diagnostics((diagnostic,)) + + assert len(summary) == operator_module._RELOAD_LOG_SUMMARY_LIMIT + assert summary.endswith("...") + + def test_refresh_reconciliation_failure_rolls_back_and_can_retry( + self, + tmp_path, + monkeypatch, + caplog, + ): + workflow_file = tmp_path / "flow.py" + workflow_file.write_text( + "import avalanche as ava\n" "@ava.workflow\n" "def flow():\n" " return None\n" + ) + operator = Operator( + workflow_paths=[str(workflow_file)], + webhook_port=0, + schedule=False, + watch=False, + ) + previous = operator._registry.view + real_reconcile = operator._webhooks.reconcile + reject_candidate = True + + def reconcile(routes: dict[str, WebhookRoute]) -> None: + nonlocal reject_candidate + if routes and reject_candidate: + reject_candidate = False + raise OSError("occupied " + ("port" * 1_000)) + real_reconcile(routes) + + monkeypatch.setattr(operator._webhooks, "reconcile", reconcile) + caplog.set_level("INFO", logger="runtime.operator.operator") + try: + workflow_file.write_text( + "import avalanche as ava\n" + "@ava.workflow(webhook=True)\n" + "def flow():\n" + " return None\n" + ) + operator._refresh_workflows() + + assert operator._registry.view is previous + assert "Workflow reload reconciliation failed" in caplog.text + failure_record = next( + record + for record in caplog.records + if "reconciliation failed" in record.getMessage() + ) + assert len(failure_record.getMessage()) < 2_200 + + workflow_file.write_text( + "import avalanche as ava\n" + "@ava.workflow(cron='5 * * * *', webhook=True)\n" + "def flow():\n" + " return None\n" + ) + operator._refresh_workflows() + + assert operator.get_catalog().revision == previous.revision + 1 + assert "Workflow reload succeeded" in caplog.text + finally: + operator.close() @pytest.mark.parametrize( "factory", @@ -447,7 +590,7 @@ def _make_operator(self): def test_subscribe_receives_updates(self): op = self._make_operator() - q = op.subscribe_run_updates() + q = op.subscribe_operator_updates() run_id = op.start_run("simple_workflow") @@ -467,7 +610,7 @@ def test_subscribe_receives_updates(self): updates.append(q.get_nowait().update) break - op.unsubscribe_run_updates(q) + op.unsubscribe_operator_updates(q) # Every accepted mutation is delivered once in global sequence order. assert len(updates) >= 2 @@ -485,8 +628,8 @@ def test_replays_exact_missed_updates_within_retained_history(self): run.status = RunStatus.SUCCESS op._notify_run(run) - assert op.subscribe_run_updates(op.operator_instance_id, 3).empty() - replay = op.subscribe_run_updates(op.operator_instance_id, 1) + assert op.subscribe_operator_updates(op.operator_instance_id, 3).empty() + replay = op.subscribe_operator_updates(op.operator_instance_id, 1) envelopes = [replay.get_nowait() for _ in range(2)] assert [item.update.sequence for item in envelopes] == [2, 3] @@ -510,7 +653,7 @@ def test_old_update_cursor_requires_structural_reset(self): run.status = RunStatus.SUCCESS op._notify_run(run) - recovery = op.subscribe_run_updates(op.operator_instance_id, 0) + recovery = op.subscribe_operator_updates(op.operator_instance_id, 0) reset = recovery.get_nowait() assert reset.reset_required.history_floor == 2 @@ -523,7 +666,7 @@ def test_old_update_cursor_requires_structural_reset(self): def test_cursor_ahead_after_restart_requires_structural_reset(self): op = Operator([], watch=False, schedule=False) try: - recovery = op.subscribe_run_updates("previous-operator", 99) + recovery = op.subscribe_operator_updates("previous-operator", 99) reset = recovery.get_nowait() assert reset.operator_instance_id == op.operator_instance_id @@ -543,7 +686,7 @@ def test_subscribe_notify_race_never_misses_or_duplicates_boundary_update(self): def subscribe(): barrier.wait() - subscriptions.append(op.subscribe_run_updates(op.operator_instance_id, 0)) + subscriptions.append(op.subscribe_operator_updates(op.operator_instance_id, 0)) def notify(): barrier.wait() @@ -647,9 +790,27 @@ def test_operator_merges_ordered_evidence_and_final_trace(self): "kind": "evidence", "invocation_id": "agent-invocation", "sequence": 1, - "event_kind": "code.generated", + "event_kind": "iteration.recorded", "timestamp_ns": 10, - "data": {"iteration": 1, "code": "print('ok')"}, + "data": { + "iteration": 1, + "duration_ms": 12, + "error": False, + "tool_count": 1, + "predict_count": 1, + "step": { + "iteration": 1, + "reasoning": "Inspect", + "code": "print('ok')", + "output": "ok", + "untruncated_output": "ok", + "error": False, + "duration_ms": 12, + "tool_calls": [{"name": "lookup", "result": "ok"}], + "predict_calls": [{"signature": "Answer", "calls": [{}]}], + "usage": {"main": {"input_tokens": 4}}, + }, + }, }, } assert operator._apply_event(run.run_id, handle, evidence) is False @@ -666,6 +827,13 @@ def test_operator_merges_ordered_evidence_and_final_trace(self): "invocation_id": "agent-invocation", "trace": { "status": "completed", + "model": "main", + "sub_model": "sub", + "iterations": 1, + "max_iterations": 4, + "duration_ms": 125, + "usage": {"main": {"input_tokens": 12}, "sub": {}}, + "telemetry_ref": {"trace_id": "trace-1"}, "evidence": { "run_id": "agent-run", "complete": True, @@ -695,17 +863,22 @@ def test_operator_merges_ordered_evidence_and_final_trace(self): assert node.trace.available is True assert node.trace.complete is True assert node.trace.event_count == 1 + assert node.trace.header is not None + assert node.trace.header.model == "main" + assert node.trace.header.iterations == 1 + assert json.loads(node.trace.header.usage_json)["main"]["input_tokens"] == 12 + assert json.loads(node.trace.header.telemetry_json)["trace_id"] == "trace-1" events = operator.list_agent_events(page_token=node.event_page_token) assert [item.event_sequence for item in events.events] == [1] + assert events.events[0].event_kind == "iteration.recorded" + assert events.events[0].iteration == 1 + assert events.events[0].tool_count == 1 + assert events.events[0].predict_count == 1 structured_event = json.loads(operator.read_detail(events.events[0].body_token)) - assert structured_event == { - "sequence": 1, - "invocation_id": "agent-invocation", - "event_kind": "code.generated", - "timestamp_ns": 10, - "data": {"iteration": 1, "code": "print('ok')"}, - } + assert structured_event["data"]["step"]["reasoning"] == "Inspect" + assert structured_event["data"]["step"]["tool_calls"][0]["name"] == "lookup" + assert structured_event["data"]["step"]["predict_calls"][0]["signature"] == "Answer" finalized = operator.read_trace( run.run_id, @@ -716,6 +889,8 @@ def test_operator_merges_ordered_evidence_and_final_trace(self): finalized_trace = json.loads(finalized.data) assert finalized_trace["status"] == "completed" assert finalized_trace["evidence"]["run_id"] == "agent-run" + assert "steps" not in finalized_trace + assert "events" not in finalized_trace["evidence"] logs = operator.list_logs(page_token=snapshot.log_page_token) assert len(logs.logs) == 2 @@ -727,6 +902,7 @@ def test_operator_merges_ordered_evidence_and_final_trace(self): assert envelope["status"] == "completed" assert envelope["run_id"] == "agent-run" assert [item["sequence"] for item in envelope["events"]] == [1] + assert envelope["trace"]["steps"][0]["reasoning"] == "Inspect" assert [entry.node_id for entry in materialized.logs] == [ "agent_1", "agent_1", @@ -854,6 +1030,67 @@ def apply(event): assert envelope["invocation_id"] == "invocation-b" assert [ (item["invocation_id"], item["sequence"]) for item in envelope["events"] - ] == [("invocation-a", 1), ("invocation-b", 1)] + ] == [("invocation-b", 1)] finally: operator.close() + + +def test_running_snapshot_reports_server_elapsed_duration(monkeypatch): + operator = Operator([], watch=False, schedule=False) + run = RunState(run_id="run-1", flow_name="Flow") + run.nodes["agent_1"] = NodeState( + node_id="agent_1", + name="Agent", + node_type="step", + status=NodeStatus.RUNNING, + started_at=10.0, + ) + monkeypatch.setattr(operator_module.time, "monotonic", lambda: 14.5) + try: + snapshot = operator._run_snapshot_locked( + run, + summary=operator._run_summary_locked(run), + as_of_sequence=1, + ) + assert snapshot.nodes[0].running_elapsed_seconds == 4.5 + finally: + operator.close() + + +def test_prepared_run_retains_immutable_topology_after_source_metadata_changes(): + prepared = { + "display_name": "Original", + "node_ids": ["source_1", "step_1"], + "graph": {"source_1": ["step_1"], "step_1": []}, + "node_types": {"source_1": "source", "step_1": "step"}, + "display_names": {"source_1": "Source", "step_1": "Step"}, + "agent_field_schemas_json": { + "step_1": '{"inputs":[{"name":"question","type":"str","description":""}],' + '"outputs":[]}' + }, + "agent_instruction_lines": {"step_1": "Original instruction."}, + } + + run = Operator._run_from_prepared( + "run-topology", + "flow.py::original", + "Original", + "manual", + 1.0, + prepared, + ) + prepared["node_ids"].append("new_1") + prepared["graph"]["source_1"] = ["new_1"] + prepared["display_names"]["step_1"] = "Changed" + prepared["agent_field_schemas_json"]["step_1"] = '{"inputs":[],"outputs":[]}' + prepared["agent_instruction_lines"]["step_1"] = "Changed instruction." + + assert run.topology.node_ids == ("source_1", "step_1") + assert run.topology.graph == (("source_1", ("step_1",)), ("step_1", ())) + assert dict(run.topology.display_names) == {"source_1": "Source", "step_1": "Step"} + assert dict(run.topology.agent_field_schemas_json) == { + "step_1": ( + '{"inputs":[{"name":"question","type":"str","description":""}],"outputs":[]}' + ) + } + assert dict(run.topology.agent_instruction_lines) == {"step_1": "Original instruction."} diff --git a/test/operator_tests/test_operator_dev_reload.py b/test/operator_tests/test_operator_dev_reload.py index 02d2b68..6831bbc 100644 --- a/test/operator_tests/test_operator_dev_reload.py +++ b/test/operator_tests/test_operator_dev_reload.py @@ -255,8 +255,7 @@ def test_current_and_later_runs_use_live_source(tmp_path, deferred): state_b = _wait_terminal(operator, run_b) assert state_a.status == RunStatus.SUCCESS assert state_b.status == RunStatus.SUCCESS - expected_a = 2 if deferred else 1 - assert any(f"value={expected_a}" in entry.message for entry in state_a.logs) + assert any("value=2" in entry.message for entry in state_a.logs) assert any("value=2" in entry.message for entry in state_b.logs) finally: operator.close() @@ -328,19 +327,19 @@ def test_concurrent_runs_have_isolated_module_globals(tmp_path): operator.close() -def test_prepare_failure_does_not_publish_run(tmp_path): +def test_prepare_failure_publishes_failed_run(tmp_path): workflow = _write_standalone(tmp_path) operator = Operator([str(workflow)], watch=False, schedule=False) try: workflow.write_text("this is invalid Python !!!\n") - with pytest.raises(RuntimeError, match="preparation failed"): - operator.start_run("flow") - assert operator._runs == {} + run = _wait_terminal(operator, operator.start_run("flow")) + assert run.status == RunStatus.FAILED + assert any("Workflow preparation failed" in entry.message for entry in run.logs) finally: operator.close() -def test_builder_prepare_failure_does_not_publish_run(tmp_path): +def test_builder_prepare_failure_publishes_failed_run(tmp_path): workflow = _write_standalone(tmp_path) operator = Operator([str(workflow)], watch=False, schedule=False) try: @@ -350,9 +349,9 @@ def test_builder_prepare_failure_does_not_publish_run(tmp_path): "def flow():\n raise RuntimeError('build')", ) ) - with pytest.raises(RuntimeError, match="RuntimeError: build"): - operator.start_run("flow") - assert operator._runs == {} + run = _wait_terminal(operator, operator.start_run("flow")) + assert run.status == RunStatus.FAILED + assert any("RuntimeError: build" in entry.message for entry in run.logs) finally: operator.close() @@ -408,15 +407,43 @@ def Process(self, **kwargs): # noqa: N802 - mirrors multiprocessing context lambda process, _job: torn_down.append(process), ) try: - with pytest.raises(RuntimeError, match=error_match): - operator.start_run("flow") - assert operator._runs == {} + run = _wait_terminal(operator, operator.start_run("flow")) + assert run.status == RunStatus.FAILED + assert any(error_match in entry.message for entry in run.logs) assert operator._active_runs == {} assert len(torn_down) == 1 finally: operator.close() +def test_preparation_event_accepts_only_agent_invocation_field_schemas(): + field_schemas = ( + '{"inputs":[{"name":"question","type":"str","description":"Question"}],' + '"outputs":[{"name":"answer","type":"str","description":"Answer"}]}' + ) + event = { + "type": "prepared", + "node_ids": ["agent_1"], + "graph": {"agent_1": []}, + "node_types": {"agent_1": "step"}, + "display_names": {"agent_1": "Agent"}, + "display_name": "Flow", + "agent_field_schemas_json": {"agent_1": field_schemas}, + "agent_instruction_lines": {"agent_1": "Answer questions."}, + } + + assert operator_module._validate_preparation_event(event) == "prepared" + + event["agent_field_schemas_json"]["agent_1"] = ( + '{"inputs":[],"outputs":[],"instructions":"must not be retained"}' + ) + with pytest.raises( + operator_module._CoordinatorProtocolError, + match="must contain only input and output schemas", + ): + operator_module._validate_preparation_event(event) + + @pytest.mark.parametrize( "event", [ @@ -468,7 +495,7 @@ def test_malformed_run_event_terminalizes_and_cleans_up(event): operator._active_runs[run_id] = handle logs = [] operator.on_log(logs.append) - updates = operator.subscribe_run_updates() + updates = operator.subscribe_operator_updates() errors = [] def drain(): @@ -637,10 +664,10 @@ def test_cancel_request_is_non_terminal_until_coordinator_stops(tmp_path): schedule=False, cancel_grace=0.15, ) - updates = operator.subscribe_run_updates() + updates = operator.subscribe_operator_updates() try: run_id = operator.start_run("flow") - deadline = time.monotonic() + 2 + deadline = time.monotonic() + 8 while operator.get_run(run_id).status != RunStatus.RUNNING: assert time.monotonic() < deadline time.sleep(0.01) @@ -674,7 +701,7 @@ def test_slow_update_consumer_receives_ordered_descriptors_and_detail_bodies(tmp body="log.info('first')\n log.info('second')", ) operator = Operator([str(workflow)], watch=False, schedule=False) - subscription = operator.subscribe_run_updates() + subscription = operator.subscribe_operator_updates() details = [] operator.on_detail_update(details.append) try: @@ -683,12 +710,19 @@ def test_slow_update_consumer_receives_ordered_descriptors_and_detail_bodies(tmp assert terminal.status == RunStatus.SUCCESS changes = [] - while not subscription.empty(): - changes.append(subscription.get_nowait().update.change) - statuses = [change.status for change in changes if isinstance(change, RunStatusChanged)] + deadline = time.monotonic() + 5 + while True: + while not subscription.empty(): + changes.append(subscription.get_nowait().update.change) + statuses = [ + change.status for change in changes if isinstance(change, RunStatusChanged) + ] + if statuses and statuses[-1] == RunStatus.SUCCESS: + break + assert time.monotonic() < deadline + time.sleep(0.01) logs = [change for change in changes if isinstance(change, LogAppended)] - assert statuses[0] == RunStatus.RUNNING - assert statuses[-1] == RunStatus.SUCCESS + assert statuses[0] == RunStatus.PENDING assert [change.log.sequence for change in logs] == [1, 2] assert [ detail.log.message.rsplit("] ", 1)[-1] @@ -742,12 +776,19 @@ def test_preparation_timeout_kills_sigterm_ignoring_coordinator(tmp_path): " return None\n" ) started = time.monotonic() - with pytest.raises(TimeoutError, match="preparation exceeded"): - operator.start_run("flow") + run = _wait_terminal(operator, operator.start_run("flow"), timeout=8.0) + assert run.status == RunStatus.FAILED assert time.monotonic() - started < 8.0 + assert any("preparation exceeded" in entry.message for entry in run.logs) pid = int(pid_file.read_text()) - with pytest.raises(ProcessLookupError): - os.kill(pid, 0) + deadline = time.monotonic() + 3 + while True: + try: + os.kill(pid, 0) + except ProcessLookupError: + break + assert time.monotonic() < deadline + time.sleep(0.03) assert operator._active_runs == {} finally: operator.close() @@ -790,7 +831,7 @@ def test_running_cancellation_kills_sigterm_ignoring_coordinator(tmp_path): operator.close() -def test_watcher_refreshes_resource_derived_cron(tmp_path): +def test_watcher_refreshes_resource_derived_cron(tmp_path, caplog): config = tmp_path / "schedule.json" config.write_text('{"cron": "1 * * * *"}') workflow = tmp_path / "flow.py" @@ -803,6 +844,7 @@ def test_watcher_refreshes_resource_derived_cron(tmp_path): "def flow():\n" " return None\n" ) + caplog.set_level("INFO", logger="runtime.operator.operator") operator = Operator([str(tmp_path)], watch=True, schedule=False) try: assert operator.list_workflows()[0].cron == "1 * * * *" @@ -816,6 +858,10 @@ def test_watcher_refreshes_resource_derived_cron(tmp_path): raise AssertionError("resource change did not refresh workflow cron") finally: operator.close() + assert "Workflow watcher started" in caplog.text + assert "Workflow reload started" in caplog.text + assert "Workflow reload succeeded" in caplog.text + assert "Workflow watcher stopped" in caplog.text def test_watcher_refreshes_cron_imported_from_live_package_root(tmp_path): @@ -877,10 +923,11 @@ def test_close_owns_and_terminates_run_during_preparation(tmp_path): cancel_grace=0.1, ) errors: list[BaseException] = [] + run_ids: list[str] = [] def start(): try: - operator.start_run("flow") + run_ids.append(operator.start_run("flow")) except BaseException as exc: errors.append(exc) @@ -894,8 +941,9 @@ def start(): operator.close() starter.join(timeout=3.0) - assert not starter.is_alive() - assert errors + assert errors == [] + assert len(run_ids) == 1 + assert _wait_terminal(operator, run_ids[0]).status == RunStatus.CANCELLED assert operator._active_runs == {} diff --git a/test/operator_tests/test_protocol_contract.py b/test/operator_tests/test_protocol_contract.py index 94f3609..5c81b29 100644 --- a/test/operator_tests/test_protocol_contract.py +++ b/test/operator_tests/test_protocol_contract.py @@ -5,6 +5,8 @@ agent_event_descriptor_to_proto, log_record_descriptor_from_proto, log_record_descriptor_to_proto, + node_snapshot_from_proto, + node_snapshot_to_proto, run_snapshot_from_proto, run_snapshot_to_proto, ) @@ -18,6 +20,8 @@ RunStatus, RunSummary, TraceDescriptor, + TraceHeader, + WorkflowTopology, ) from runtime.operator.operator import Operator from runtime.operator.proto import operator_pb2 as pb @@ -35,10 +39,12 @@ def test_structural_snapshot_contract_excludes_detail_bodies(): "nodes", "latest_log_sequence", "log_page_token", + "topology", } assert "logs" not in snapshot_fields assert "agent_trace_json" not in node_fields assert "event_page_token" in node_fields + assert "running_elapsed_seconds" in node_fields assert "logs" not in summary_fields assert "trace" not in summary_fields snapshot_request_fields = pb.GetRunSnapshotRequest.DESCRIPTOR.fields_by_name @@ -67,6 +73,16 @@ def test_snapshot_detail_cursor_and_descriptor_roundtrip(): event_count=42, size_bytes=5_000_000, latest_event_sequence=42, + header=TraceHeader( + status="completed", + model="main", + sub_model="sub", + iterations=3, + max_iterations=5, + duration_ms=1250, + usage_json='{"main":{"input_tokens":12}}', + telemetry_json='{"trace_id":"trace-1"}', + ), ) snapshot = RunSnapshot( operator_instance_id="operator-1", @@ -75,6 +91,7 @@ def test_snapshot_detail_cursor_and_descriptor_roundtrip(): run_id="run-1", flow_name="example", status=RunStatus.RUNNING, + triggered_at=1_704_067_200.0, workflow_id="flow.py::example", workflow_display_name="Example", created_sequence=2, @@ -85,14 +102,29 @@ def test_snapshot_detail_cursor_and_descriptor_roundtrip(): node_id="agent_1", name="Agent", node_type="step", - status=NodeStatus.SUCCESS, + status=NodeStatus.RUNNING, trace=descriptor, revision=17, + started_at=10.0, + running_elapsed_seconds=4.5, event_page_token="events-token", ), ), latest_log_sequence=22, log_page_token="logs-token", + topology=WorkflowTopology( + node_ids=("agent_1",), + graph=(("agent_1", ()),), + node_types=(("agent_1", "step"),), + display_names=(("agent_1", "Agent"),), + agent_field_schemas_json=( + ( + "agent_1", + '{"inputs":[],"outputs":[{"name":"answer","type":"str",' + '"description":""}]}', + ), + ), + ), ) assert run_snapshot_from_proto(run_snapshot_to_proto(snapshot)) == snapshot @@ -112,7 +144,21 @@ def test_detail_records_expose_only_bounded_metadata(): event_sequence=7, size_bytes=5_000_000, body_token="opaque-event-token", + event_kind="iteration.recorded", + iteration=3, + duration_ms=1250, + error=True, + tool_count=2, + predict_count=4, + ) + failed = NodeSnapshot( + node_id="failed", + name="Failed", + node_type="step", + status=NodeStatus.FAILED, + error="invalid customer record", ) + assert node_snapshot_from_proto(node_snapshot_to_proto(failed)) == failed assert log_record_descriptor_from_proto(log_record_descriptor_to_proto(log)) == log assert agent_event_descriptor_from_proto(agent_event_descriptor_to_proto(event)) == event @@ -121,9 +167,9 @@ def test_detail_records_expose_only_bounded_metadata(): def test_update_envelope_distinguishes_changes_from_reset(): - update = pb.RunUpdateEnvelope( + update = pb.OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=24, node_status_changed=pb.NodeStatusChanged( run_id="run-1", @@ -133,7 +179,7 @@ def test_update_envelope_distinguishes_changes_from_reset(): ), ), ) - reset = pb.RunUpdateEnvelope( + reset = pb.OperatorUpdateEnvelope( operator_instance_id="operator-2", reset_required=pb.ResetRequired(history_floor=100, latest_sequence=200), ) @@ -144,10 +190,10 @@ def test_update_envelope_distinguishes_changes_from_reset(): def test_run_update_is_a_sequenced_typed_change_record(): - update_fields = pb.RunUpdate.DESCRIPTOR.fields_by_name - change_fields = pb.RunUpdate.DESCRIPTOR.oneofs_by_name["change"].fields - envelope_fields = pb.RunUpdateEnvelope.DESCRIPTOR.fields_by_name - payload_fields = pb.RunUpdateEnvelope.DESCRIPTOR.oneofs_by_name["payload"].fields + update_fields = pb.OperatorUpdate.DESCRIPTOR.fields_by_name + change_fields = pb.OperatorUpdate.DESCRIPTOR.oneofs_by_name["change"].fields + envelope_fields = pb.OperatorUpdateEnvelope.DESCRIPTOR.fields_by_name + payload_fields = pb.OperatorUpdateEnvelope.DESCRIPTOR.oneofs_by_name["payload"].fields assert {name: field.number for name, field in update_fields.items()} == { "sequence": 1, @@ -157,6 +203,7 @@ def test_run_update_is_a_sequenced_typed_change_record(): "log_appended": 5, "agent_event_appended": 6, "trace_finalized": 7, + "catalog_replaced": 8, } assert [field.name for field in change_fields] == [ "run_created", @@ -165,6 +212,7 @@ def test_run_update_is_a_sequenced_typed_change_record(): "log_appended", "agent_event_appended", "trace_finalized", + "catalog_replaced", ] assert "run" not in update_fields assert {name: field.number for name, field in envelope_fields.items()} == { @@ -197,10 +245,10 @@ def test_service_exposes_parallel_workstream_contracts(): "ListLogs", "ListAgentEvents", "ReadTrace", - "StreamRunUpdates", + "StreamOperatorUpdates", } <= set(methods) assert methods["ReadTrace"].server_streaming is True - assert methods["StreamRunUpdates"].server_streaming is True + assert methods["StreamOperatorUpdates"].server_streaming is True assert methods["ReadDetail"].server_streaming is True diff --git a/test/operator_tests/test_registry.py b/test/operator_tests/test_registry.py index de4aeea..8cf66fb 100644 --- a/test/operator_tests/test_registry.py +++ b/test/operator_tests/test_registry.py @@ -18,6 +18,10 @@ workflow_to_info, ) from runtime.operator.discovery import configure_roots +from runtime.operator.registry import ( + agent_field_schemas_for_workflow, + agent_instruction_lines_for_workflow, +) FIXTURES_DIR = os.path.join(os.path.dirname(os.path.dirname(__file__)), "fixtures") @@ -274,7 +278,23 @@ def test_two_roots_with_same_package_are_discovered_and_runnable_independently( assert registry.get_builder(descriptors[0].workflow_id)().name == "left_build" assert registry.get_builder(descriptors[1].workflow_id)().name == "right_build" - def test_refresh_invalid_file_removes_current_descriptor(self, tmp_path): + def test_rescan_of_unchanged_catalog_preserves_revision_and_view(self, tmp_path): + workflow_file = tmp_path / "flow.py" + workflow_file.write_text( + "import avalanche as ava\n" + "@ava.workflow\n" + "def unchanged():\n" + " return None\n" + ) + registry = WorkflowRegistry() + initial = registry.scan([str(workflow_file)]) + + rescanned = registry.rescan() + + assert rescanned is initial + assert rescanned.revision == initial.revision + + def test_refresh_invalid_file_retains_current_descriptor(self, tmp_path): workflow_file = tmp_path / "flow.py" workflow_file.write_text( "import avalanche as ava\n" @@ -289,10 +309,10 @@ def test_refresh_invalid_file_removes_current_descriptor(self, tmp_path): workflow_file.write_text("this is not valid Python !!!\n") registry.rescan() - assert registry.descriptors() == () + assert [item.workflow_id for item in registry.descriptors()] == ["flow.py::scheduled"] assert registry.list_diagnostics()[0].kind == "import_error" - def test_discovery_timeout_installs_empty_current_view(self, tmp_path): + def test_discovery_timeout_retains_current_view(self, tmp_path): workflow_file = tmp_path / "flow.py" workflow_file.write_text( "import avalanche as ava\n" @@ -300,7 +320,7 @@ def test_discovery_timeout_installs_empty_current_view(self, tmp_path): "def scheduled():\n" " return None\n" ) - registry = WorkflowRegistry(discovery_timeout=2.0) + registry = WorkflowRegistry(discovery_timeout=5.0) registry.scan([str(workflow_file)]) assert registry.descriptors() @@ -310,7 +330,7 @@ def test_discovery_timeout_installs_empty_current_view(self, tmp_path): registry.rescan() assert time.monotonic() - started < 2.0 - assert registry.descriptors() == () + assert [item.workflow_id for item in registry.descriptors()] == ["flow.py::scheduled"] assert "exceeded 0.2s" in registry.list_diagnostics()[0].message def test_discovery_stdout_and_delayed_background_output_do_not_corrupt_result( @@ -328,7 +348,7 @@ def test_discovery_stdout_and_delayed_background_output_do_not_corrupt_result( " print('builder noise')\n" ) - registry = WorkflowRegistry(discovery_timeout=2.0) + registry = WorkflowRegistry(discovery_timeout=10.0) registry.scan([str(workflow_file)]) assert [item.workflow_id for item in registry.descriptors()] == ["flow.py::noisy"] @@ -348,7 +368,7 @@ def test_successful_discovery_terminates_import_spawned_descendant(self, tmp_pat " return None\n" ) - registry = WorkflowRegistry(discovery_timeout=2.0) + registry = WorkflowRegistry(discovery_timeout=10.0) registry.scan([str(workflow_file)]) assert registry.resolve("spawned") @@ -395,7 +415,7 @@ def test_explicit_alias_ids_are_stable_after_root_relocation(self, tmp_path): assert tuple(first.view.by_id) == tuple(second.view.by_id) - def test_duplicate_canonical_ids_are_rejected(self, monkeypatch): + def test_duplicate_canonical_ids_publish_invalid_catalog_diagnostic(self, monkeypatch): from avalanche.operator.models import WorkflowDescriptor, WorkflowLocator descriptor = WorkflowDescriptor( @@ -411,8 +431,10 @@ def test_duplicate_canonical_ids_are_rejected(self, monkeypatch): "runtime.operator.registry.discover", lambda roots, timeout: ((descriptor, descriptor), ()), ) - with pytest.raises(ValueError, match="Duplicate canonical workflow ID"): - WorkflowRegistry().scan(["root=/tmp"]) + registry = WorkflowRegistry() + registry.scan(["root=/tmp"]) + assert registry.descriptors() == () + assert [item.kind for item in registry.list_diagnostics()] == ["invalid_catalog"] def test_sequential_package_scans_isolate_identical_module_names(self, tmp_path): first = tmp_path / "first" @@ -615,6 +637,16 @@ def agent_flow(): metadata = json.loads(info.agent_metadata_json["analyze_1"]) assert metadata["signature"]["name"] == "Analyze" assert metadata["runtime"]["max_iterations"] == 4 + field_schemas = json.loads( + agent_field_schemas_for_workflow(workflow, ["analyze_1"])["analyze_1"] + ) + assert field_schemas == { + "inputs": [{"name": "text", "type": "str", "description": "text to analyze"}], + "outputs": [{"name": "result", "type": "str", "description": "analysis"}], + } + assert agent_instruction_lines_for_workflow(workflow, ["analyze_1"]) == { + "analyze_1": "Analyze text." + } spec = workflow.nodes["analyze_1"].node.fn.__agent_step__ diff --git a/test/operator_tests/test_run_updates.py b/test/operator_tests/test_run_updates.py index 3c478c5..b8511be 100644 --- a/test/operator_tests/test_run_updates.py +++ b/test/operator_tests/test_run_updates.py @@ -15,14 +15,15 @@ _RunUpdateResetError, ) from runtime.operator.convert import ( - run_update_envelope_from_proto, - run_update_envelope_to_proto, + operator_update_envelope_from_proto, + operator_update_envelope_to_proto, ) from runtime.operator.models import ( AgentEvent, AgentEventAppended, AgentEventDescriptor, AgentEventDetailAppended, + CatalogSnapshot, LogAppended, LogDetailAppended, LogEntry, @@ -32,6 +33,8 @@ NodeState, NodeStatus, NodeStatusChanged, + OperatorUpdate, + OperatorUpdateEnvelope, ResetBaseline, ResetRequired, RunCreated, @@ -40,8 +43,6 @@ RunStatus, RunStatusChanged, RunSummary, - RunUpdate, - RunUpdateEnvelope, TraceDescriptor, TraceFinalized, ) @@ -64,10 +65,10 @@ def _drain(subscription): return values -def _created(sequence: int = 1, *, epoch: str = "operator-1") -> RunUpdateEnvelope: - return RunUpdateEnvelope( +def _created(sequence: int = 1, *, epoch: str = "operator-1") -> OperatorUpdateEnvelope: + return OperatorUpdateEnvelope( operator_instance_id=epoch, - update=RunUpdate( + update=OperatorUpdate( sequence=sequence, change=RunCreated( summary=RunSummary( @@ -96,7 +97,14 @@ def test_typed_update_envelopes_roundtrip_all_changes(): changes = [ _created().update.change, RunStatusChanged("run-1", RunStatus.RUNNING, started_at=1.0, revision=2), - NodeStatusChanged("run-1", "node-1", NodeStatus.SUCCESS, ended_at=2.0, revision=3), + NodeStatusChanged( + "run-1", + "node-1", + NodeStatus.RUNNING, + started_at=2.0, + running_elapsed_seconds=0.5, + revision=3, + ), LogAppended( "run-1", LogRecordDescriptor( @@ -128,12 +136,13 @@ def test_typed_update_envelopes_roundtrip_all_changes(): ] for sequence, change in enumerate(changes, start=1): - envelope = RunUpdateEnvelope( + envelope = OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate(sequence=sequence, change=change), + update=OperatorUpdate(sequence=sequence, change=change), ) assert ( - run_update_envelope_from_proto(run_update_envelope_to_proto(envelope)) == envelope + operator_update_envelope_from_proto(operator_update_envelope_to_proto(envelope)) + == envelope ) @@ -197,7 +206,9 @@ def test_operator_replays_typed_updates_in_order(): }, ) - envelopes = _drain(operator.subscribe_run_updates(operator.operator_instance_id, 0)) + envelopes = _drain( + operator.subscribe_operator_updates(operator.operator_instance_id, 0) + ) assert [envelope.update.sequence for envelope in envelopes] == list( range(1, operator.current_sequence + 1) ) @@ -213,7 +224,7 @@ def test_operator_replays_typed_updates_in_order(): TraceFinalized, ] replay = _drain( - operator.subscribe_run_updates( + operator.subscribe_operator_updates( operator.operator_instance_id, envelopes[2].update.sequence, ) @@ -233,7 +244,7 @@ def test_stale_cursor_and_epoch_explicitly_require_reset(): run.status = status operator._notify_run(run) - stale_cursor = operator.subscribe_run_updates(operator.operator_instance_id, 0) + stale_cursor = operator.subscribe_operator_updates(operator.operator_instance_id, 0) cursor_reset = stale_cursor.get_nowait() assert cursor_reset.update is None assert cursor_reset.reset_required == ResetRequired( @@ -241,7 +252,7 @@ def test_stale_cursor_and_epoch_explicitly_require_reset(): latest_sequence=3, ) - stale_epoch = operator.subscribe_run_updates("previous-operator", 3) + stale_epoch = operator.subscribe_operator_updates("previous-operator", 3) epoch_reset = stale_epoch.get_nowait() assert epoch_reset.operator_instance_id == operator.operator_instance_id assert epoch_reset.reset_required is not None @@ -262,7 +273,7 @@ def test_slow_update_consumer_gets_bounded_overflow_reset_on_terminal_update(): operator._runs[run.run_id] = run try: operator._notify_run(run) - subscription = operator.subscribe_run_updates( + subscription = operator.subscribe_operator_updates( operator.operator_instance_id, operator.current_sequence, ) @@ -305,7 +316,7 @@ def test_operator_restart_rejects_previous_epoch_cursor(): first._runs[run.run_id] = run first._notify_run(run) - subscription = second.subscribe_run_updates( + subscription = second.subscribe_operator_updates( first.operator_instance_id, first.current_sequence, ) @@ -341,7 +352,7 @@ def test_bounded_journal_retains_updates_not_run_state_snapshots(): ) assert len(operator._stream_history) == 2 - assert all(isinstance(item, RunUpdate) for item in operator._stream_history) + assert all(isinstance(item, OperatorUpdate) for item in operator._stream_history) assert all(isinstance(item.change, LogAppended) for item in operator._stream_history) assert [item.change.log.size_bytes for item in operator._stream_history] == [ 65_536, @@ -372,9 +383,9 @@ def test_client_applies_ordered_updates_and_ignores_duplicates(): run, _ = provider._apply_update_envelope(_created()) assert run.status == RunStatus.PENDING - status = RunUpdateEnvelope( + status = OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=2, change=RunStatusChanged("run-1", RunStatus.RUNNING, started_at=1.0, revision=2), ), @@ -384,9 +395,9 @@ def test_client_applies_ordered_updates_and_ignores_duplicates(): assert provider._apply_update_envelope(status) == (None, None) assert provider._cursor.sequence == 2 - node_update = RunUpdateEnvelope( + node_update = OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=3, change=NodeStatusChanged( "run-1", @@ -404,9 +415,9 @@ def test_client_applies_ordered_updates_and_ignores_duplicates(): "log-token": b"complete", "event-token": b'{"sequence":2,"event_kind":"code.executed","data":{}}', }[token] - log_update = RunUpdateEnvelope( + log_update = OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=4, change=LogAppended( "run-1", @@ -427,9 +438,9 @@ def test_client_applies_ordered_updates_and_ignores_duplicates(): assert run.logs == [] assert run.latest_log_sequence == 1 - event_update = RunUpdateEnvelope( + event_update = OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=5, change=AgentEventAppended( "run-1", @@ -455,9 +466,9 @@ def test_client_applies_ordered_updates_and_ignores_duplicates(): {"sequence": 2, "event_kind": "code.executed", "data": {}} ] - trace_update = RunUpdateEnvelope( + trace_update = OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=6, change=TraceFinalized( "run-1", @@ -485,9 +496,9 @@ def test_client_applies_ordered_updates_and_ignores_duplicates(): provider._hydrated_trace_revisions[key] = 6 run, _ = provider._apply_update_envelope( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=7, change=TraceFinalized( "run-1", @@ -514,9 +525,9 @@ def test_client_applies_ordered_updates_and_ignores_duplicates(): with pytest.raises(_RunUpdateResetError, match="sequence gap"): provider._apply_update_envelope( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=9, change=RunStatusChanged("run-1", RunStatus.SUCCESS, revision=8), ), @@ -558,9 +569,9 @@ def append(self, item): message=str(log_sequence), ) run, detail = provider._apply_update_envelope_locked( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=log_sequence + 1, change=LogAppended( "run-1", @@ -602,9 +613,9 @@ def test_client_detail_cache_evicts_oldest_buckets_within_count_and_byte_limits( run_id = f"run-{index}" sequence += 1 provider._apply_update_envelope( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=sequence, change=RunCreated( summary=RunSummary( @@ -620,9 +631,9 @@ def test_client_detail_cache_evicts_oldest_buckets_within_count_and_byte_limits( ) sequence += 1 provider._apply_update_envelope( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=sequence, change=LogAppended( run_id, @@ -659,9 +670,9 @@ def test_client_detail_cache_evicts_oldest_buckets_within_count_and_byte_limits( assert provider._log_entries == {} provider._apply_update_envelope( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-2", - update=RunUpdate( + update=OperatorUpdate( sequence=sequence + 2, change=RunCreated( summary=RunSummary( @@ -676,9 +687,9 @@ def test_client_detail_cache_evicts_oldest_buckets_within_count_and_byte_limits( ) ) provider._apply_update_envelope( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-2", - update=RunUpdate( + update=OperatorUpdate( sequence=sequence + 3, change=LogAppended( "run-after-reset", @@ -731,9 +742,9 @@ def parse_one_event(value, *args, **kwargs): guarded.setattr(client_module.json, "loads", parse_one_event) with provider._state_lock: status_run, _ = provider._apply_update_envelope_locked( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=2, change=RunStatusChanged( "run-1", @@ -749,9 +760,9 @@ def parse_one_event(value, *args, **kwargs): assert status_run.logs is initial.logs node_run, _ = provider._apply_update_envelope_locked( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=3, change=NodeStatusChanged( "run-1", @@ -775,9 +786,9 @@ def parse_one_event(value, *args, **kwargs): message="complete", ) log_run, _ = provider._apply_update_envelope_locked( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=4, change=LogAppended( "run-1", @@ -810,9 +821,9 @@ def parse_one_event(value, *args, **kwargs): } ) event_run, _ = provider._apply_update_envelope_locked( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=event_sequence + 4, change=AgentEventAppended( "run-1", @@ -1284,9 +1295,9 @@ def load_authoritative_baseline(load_snapshot): assert provider._runs_by_id["run-1"] is baseline run, _ = provider._apply_update_envelope( - RunUpdateEnvelope( + OperatorUpdateEnvelope( operator_instance_id="operator-1", - update=RunUpdate( + update=OperatorUpdate( sequence=4, change=RunStatusChanged( "run-1", @@ -1308,13 +1319,13 @@ def test_client_resets_baseline_and_resumes_after_operator_restart(): class RestartedStub: stream_calls = 0 - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 assert metadata is None self.stream_calls += 1 if self.stream_calls == 1: assert request.operator_instance_id == "old-operator" assert request.after_sequence == 99 - yield pb.RunUpdateEnvelope( + yield pb.OperatorUpdateEnvelope( operator_instance_id="new-operator", reset_required=pb.ResetRequired( history_floor=1, @@ -1324,9 +1335,9 @@ def StreamRunUpdates(self, request, *, metadata): # noqa: N802 return assert request.operator_instance_id == "new-operator" assert request.after_sequence == 2 - yield pb.RunUpdateEnvelope( + yield pb.OperatorUpdateEnvelope( operator_instance_id="new-operator", - update=pb.RunUpdate( + update=pb.OperatorUpdate( sequence=3, run_status_changed=pb.RunStatusChanged( run_id="run-1", @@ -1350,7 +1361,7 @@ def StreamRunUpdates(self, request, *, metadata): # noqa: N802 generation=notice.generation, operator_instance_id="new-operator", as_of_sequence=2, - workflows=(), + catalog=CatalogSnapshot(workflows=()), runs_by_workflow={"flow": (baseline,)}, ) diff --git a/test/operator_tests/test_state_detail.py b/test/operator_tests/test_state_detail.py index 6490c64..c604a21 100644 --- a/test/operator_tests/test_state_detail.py +++ b/test/operator_tests/test_state_detail.py @@ -11,8 +11,8 @@ import pytest from avalanche.operator import Operator -from avalanche.operator.client import GrpcStateProvider, StreamState -from avalanche.operator.convert import run_update_envelope_to_proto +from avalanche.operator.client import GrpcStateProvider, OperatorCallError, StreamState +from avalanche.operator.convert import operator_update_envelope_to_proto from avalanche.operator.models import ( AgentEvent, AgentEventDetailAppended, @@ -20,13 +20,14 @@ LogEntry, LogLevel, NodeState, + OperatorUpdateEnvelope, RunState, RunStatus, RunStatusChanged, - RunUpdateEnvelope, SequencedLogEntry, ) from avalanche.operator.server import TRACE_CHUNK_BYTES, serve +from runtime.operator.operator import _decode_transport_token, _encode_transport_token from runtime.operator.proto import operator_pb2 as pb from runtime.operator.proto import operator_pb2_grpc as pb_grpc from runtime.operator.scheduler import Scheduler @@ -199,6 +200,50 @@ def test_structural_snapshot_excludes_detail_bodies_while_explicit_read_material operator.close() +def test_latest_run_snapshot_client_is_typed_and_rejects_a_stale_operator_epoch(): + stale_operator = Operator(watch=False, schedule=False) + stale_operator_instance_id = stale_operator.operator_instance_id + stale_operator.close() + operator = Operator(watch=False, schedule=False) + server = None + provider = None + try: + run = _add_run(operator, "run-latest") + port = _unused_port() + server = serve(operator, port=port, block=False) + provider = GrpcStateProvider(f"localhost:{port}") + + initial = provider.get_latest_run_snapshot( + run.run_id, + operator.operator_instance_id, + ) + operator._apply_event( + run.run_id, + _event_handle(), + {"type": "running", "timestamp": 1.0}, + ) + latest = provider.get_latest_run_snapshot( + run.run_id, + operator.operator_instance_id, + ) + + assert initial.summary.run_id == run.run_id + assert initial.summary.status is RunStatus.PENDING + assert latest.operator_instance_id == operator.operator_instance_id + assert latest.as_of_sequence > initial.as_of_sequence + assert latest.summary.status is RunStatus.RUNNING + + with pytest.raises(OperatorCallError) as error: + provider.get_latest_run_snapshot(run.run_id, stale_operator_instance_id) + assert error.value.status is grpc.StatusCode.FAILED_PRECONDITION + finally: + if provider is not None: + provider.close() + if server is not None: + server.stop(grace=0).wait() + operator.close() + + def test_log_and_agent_event_pagination_use_exclusive_deduplicating_cursors(): operator = Operator(watch=False, schedule=False) try: @@ -242,6 +287,301 @@ def test_log_and_agent_event_pagination_use_exclusive_deduplicating_cursors(): operator.close() +def test_exact_node_log_pages_use_the_append_only_node_index(): + class CountingLogs(list): + def __init__(self, entries): + super().__init__(entries) + self.item_reads = 0 + + def __getitem__(self, index): + if isinstance(index, int): + self.item_reads += 1 + return super().__getitem__(index) + + operator = Operator(watch=False, schedule=False) + try: + run = _add_run(operator, "run-sparse-logs") + timestamp = datetime.now() + target_entry = LogEntry( + timestamp=timestamp, + level=LogLevel.INFO, + node_id="agent_1", + message="", + ) + other_entry = LogEntry( + timestamp=timestamp, + level=LogLevel.INFO, + node_id="other", + message="", + ) + with operator._lock: + for sequence in range(1, 100_001): + entry = ( + target_entry + if sequence == 50_000 or sequence == 100_000 + else other_entry + ) + operator._append_log_unchecked_locked(run, entry, 0) + counted_logs = CountingLogs(operator._logs[run.run_id]) + operator._logs[run.run_id] = counted_logs + + missing = operator.list_logs( + run.run_id, + page_size=1, + node_id="missing", + ) + assert missing.logs == () + assert counted_logs.item_reads <= 1 + + first = operator.list_logs( + run.run_id, + page_size=1, + node_id="agent_1", + ) + second = operator.list_logs( + page_token=first.next_page_token, + after_sequence=first.logs[-1].sequence, + page_size=1, + node_id="agent_1", + ) + newest = operator.list_logs( + run.run_id, + page_size=2, + node_id="agent_1", + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + + assert [item.sequence for item in first.logs] == [50_000] + assert [item.sequence for item in second.logs] == [100_000] + assert [item.sequence for item in newest.logs] == [100_000, 50_000] + assert counted_logs.item_reads <= 8 + finally: + operator.close() + + +def test_failed_run_publication_discards_its_log_sequence_index(): + class FailingPublicationOperator(Operator): + def _publish_run_locked(self, run, *args, **kwargs): + self._log_sequences_by_node[run.run_id] = {"agent_1": [1]} + raise RuntimeError("publication failed") + + fixture = Path(__file__).parents[1] / "fixtures" / "sample_workflows.py" + operator = FailingPublicationOperator( + workflow_paths=[str(fixture)], + watch=False, + schedule=False, + ) + try: + with pytest.raises(RuntimeError, match="publication failed"): + operator.start_run("simple_workflow", run_id="run-failed-publication") + + assert "run-failed-publication" not in operator._log_sequences_by_node + finally: + operator.close() + + +def test_newest_first_pages_reconstruct_filtered_snapshot_without_duplicates(): + operator = Operator(watch=False, schedule=False) + try: + run = _add_run(operator, "run-newest") + with operator._lock: + run.nodes["agent_2"] = NodeState( + node_id="agent_2", + name="Other", + node_type="step", + ) + for sequence in range(1, 6): + operator._apply_event( + run.run_id, + _event_handle(), + { + "type": "log", + "timestamp": float(sequence), + "level": logging.INFO, + "node_id": "agent_1" if sequence % 2 else "agent_2", + "message": f"log-{sequence}", + }, + ) + operator._apply_event( + run.run_id, + _event_handle(), + _evidence(sequence), + ) + + snapshot = operator.get_latest_run_snapshot( + run.run_id, + operator_instance_id=operator.operator_instance_id, + ) + assert snapshot is not None + operator._apply_event( + run.run_id, + _event_handle(), + { + "type": "log", + "timestamp": 100.0, + "level": logging.INFO, + "node_id": "agent_1", + "message": "after-snapshot", + }, + ) + operator._apply_event(run.run_id, _event_handle(), _evidence(6)) + + forward_logs = operator.list_logs( + page_token=snapshot.log_page_token, + page_size=100, + node_id="agent_1", + ) + newest_log_sequences = [] + newest_log_descriptors = [] + token = snapshot.log_page_token + before_sequence = 0 + while token: + page = operator.list_logs( + page_token=token, + page_size=2, + before_sequence=before_sequence, + node_id="agent_1", + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + newest_log_sequences.extend(item.sequence for item in page.logs) + newest_log_descriptors.extend(page.logs) + before_sequence = page.logs[-1].sequence if page.logs else 0 + token = page.next_page_token + + forward_events = operator.list_agent_events( + page_token=snapshot.nodes[0].event_page_token, + page_size=100, + ) + newest_event_sequences = [] + token = snapshot.nodes[0].event_page_token + before_event_sequence = 0 + while token: + page = operator.list_agent_events( + page_token=token, + page_size=2, + before_event_sequence=before_event_sequence, + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + newest_event_sequences.extend( + item.event_sequence for item in page.events + ) + before_event_sequence = ( + page.events[-1].event_sequence if page.events else 0 + ) + token = page.next_page_token + + forward_log_sequences = [item.sequence for item in forward_logs.logs] + forward_event_sequences = [ + item.event_sequence for item in forward_events.events + ] + assert newest_log_sequences[::-1] == forward_log_sequences + assert newest_event_sequences[::-1] == forward_event_sequences + assert len(newest_log_sequences) == len(set(newest_log_sequences)) + assert len(newest_event_sequences) == len(set(newest_event_sequences)) + assert {item.node_id for item in newest_log_descriptors} == {"agent_1"} + assert all( + sequence <= snapshot.latest_log_sequence + for sequence in newest_log_sequences + ) + bodies = [] + for descriptor in newest_log_descriptors: + body_token = _decode_transport_token( + descriptor.body_token, + "log-body", + ) + assert body_token["as_of_sequence"] == snapshot.as_of_sequence + bodies.append(operator.read_detail(descriptor.body_token)) + assert b"after-snapshot" not in bodies + finally: + operator.close() + + +def test_detail_continuations_reject_cursor_filter_and_direction_changes(): + operator = Operator(watch=False, schedule=False) + try: + run = _add_run(operator, "run-cursors") + for sequence in range(1, 4): + operator._apply_event( + run.run_id, + _event_handle(), + { + "type": "log", + "timestamp": float(sequence), + "level": logging.INFO, + "node_id": "agent_1", + "message": f"log-{sequence}", + }, + ) + operator._apply_event(run.run_id, _event_handle(), _evidence(sequence)) + snapshot = operator.get_latest_run_snapshot( + run.run_id, + operator_instance_id=operator.operator_instance_id, + ) + assert snapshot is not None + + first_log_page = operator.list_logs( + page_token=snapshot.log_page_token, + page_size=1, + node_id="agent_1", + ) + assert first_log_page.next_page_token + with pytest.raises(ValueError, match="cursor"): + operator.list_logs( + page_token=first_log_page.next_page_token, + after_sequence=first_log_page.logs[-1].sequence + 1, + page_size=1, + node_id="agent_1", + ) + with pytest.raises(ValueError, match="filter"): + operator.list_logs( + page_token=first_log_page.next_page_token, + after_sequence=first_log_page.logs[-1].sequence, + page_size=1, + node_id="agent_2", + ) + + newest_log_page = operator.list_logs( + page_token=snapshot.log_page_token, + page_size=1, + node_id="agent_1", + order=pb.DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST, + ) + assert newest_log_page.next_page_token + with pytest.raises(ValueError, match="order"): + operator.list_logs( + page_token=newest_log_page.next_page_token, + page_size=1, + node_id="agent_1", + ) + + first_event_page = operator.list_agent_events( + page_token=snapshot.nodes[0].event_page_token, + page_size=1, + ) + assert first_event_page.next_page_token + with pytest.raises(ValueError, match="cursor"): + operator.list_agent_events( + page_token=first_event_page.next_page_token, + after_event_sequence=first_event_page.events[-1].event_sequence + 1, + page_size=1, + ) + + decoded = _decode_transport_token( + first_event_page.next_page_token, + "events", + ) + decoded["future_token_field"] = {"version": 2} + compatible_token = _encode_transport_token(**decoded) + compatible_page = operator.list_agent_events( + page_token=compatible_token, + after_event_sequence=first_event_page.events[-1].event_sequence, + page_size=1, + ) + assert compatible_page.events + finally: + operator.close() + + def test_detail_pagination_requires_snapshot_issued_page_tokens(): operator = Operator(watch=False, schedule=False) server = None @@ -422,7 +762,7 @@ def test_start_run_publication_blocks_pagination_until_creation_is_revisioned(): start_errors = [] reader_done = threading.Event() page_holder = [] - subscription = operator.subscribe_run_updates() + subscription = operator.subscribe_operator_updates() operator.block_next_publication() def start_run() -> None: @@ -450,7 +790,7 @@ def read_page() -> None: assert not reader.is_alive() assert start_errors == [] first = subscription.get(timeout=5) - assert first.update.change.summary.status == RunStatus.PENDING + assert first.update.change.summary.status == RunStatus.REQUESTING page = page_holder[0] summary = next(item for item in page.runs if item.run_id == "run-publishing") @@ -463,7 +803,7 @@ def read_page() -> None: starter.join(timeout=1) if reader.ident is not None: reader.join(timeout=1) - operator.unsubscribe_run_updates(subscription) + operator.unsubscribe_operator_updates(subscription) operator.close() @@ -482,14 +822,18 @@ def apply_event() -> None: apply_errors.append(exc) def read_detail() -> None: - page = operator.list_run_summaries() - observed["snapshot"] = operator.get_run_snapshot( + snapshot = operator.get_latest_run_snapshot( run.run_id, - operator_instance_id=page.operator_instance_id, - as_of_sequence=page.as_of_sequence, + operator_instance_id=operator.operator_instance_id, + ) + observed["snapshot"] = snapshot + assert snapshot is not None + observed["logs"] = operator.list_logs( + page_token=snapshot.log_page_token, + ) + observed["events"] = operator.list_agent_events( + page_token=snapshot.nodes[0].event_page_token, ) - observed["logs"] = operator.list_logs(run.run_id) - observed["events"] = operator.list_agent_events(run.run_id, "agent_1") reader_done.set() publisher = threading.Thread(target=apply_event) @@ -529,7 +873,7 @@ def read_detail() -> None: def test_concurrent_publishers_dispatch_detail_callbacks_and_updates_in_order(): operator = _OrderedDeliveryOperator(watch=False, schedule=False) run = _add_run(operator, "run-ordered") - subscription = operator.subscribe_run_updates( + subscription = operator.subscribe_operator_updates( operator.operator_instance_id, operator.current_sequence ) first_callback_entered = threading.Event() @@ -604,7 +948,7 @@ def publish(message: str, timestamp: float) -> None: publisher_n.join(timeout=1) if publisher_n1.ident is not None: publisher_n1.join(timeout=1) - operator.unsubscribe_run_updates(subscription) + operator.unsubscribe_operator_updates(subscription) operator.close() assert not operator._notification_thread.is_alive() @@ -612,7 +956,7 @@ def publish(message: str, timestamp: float) -> None: def test_close_keeps_dispatcher_alive_for_notification_from_delayed_drain(): operator = Operator(watch=False, schedule=False, cancel_grace=0) run = _add_run(operator, "run-delayed-close") - subscription = operator.subscribe_run_updates( + subscription = operator.subscribe_operator_updates( operator.operator_instance_id, operator.current_sequence ) callback_statuses = [] @@ -637,6 +981,7 @@ def delayed_drain() -> None: start_event=threading.Event(), windows_job=None, drain_thread=drain, + preparation_thread=None, result_bundle=operator._result_store.prepare(), success_quiesced=False, ) @@ -670,7 +1015,7 @@ def delayed_drain() -> None: release_drain.set() if drain.ident is not None: drain.join(timeout=1) - operator.unsubscribe_run_updates(subscription) + operator.unsubscribe_operator_updates(subscription) operator.close() @@ -816,7 +1161,17 @@ def test_max_log_and_large_agent_event_use_bounded_live_and_hydration_transport( with live._state_lock: live_logs = live._log_entries.get(run.run_id) live_events = live._agent_events.get(key) - if matching and live_logs and live_events: + has_log_detail = any( + isinstance(detail, LogDetailAppended) and detail.log.message == large_log + for detail in details + ) + has_agent_detail = any( + isinstance(detail, AgentEventDetailAppended) + and json.loads(detail.event.event_json)["data"]["payload"] + == large_event_payload + for detail in details + ) + if matching and live_logs and live_events and has_log_detail and has_agent_detail: latest = matching[-1] break assert time.monotonic() < deadline @@ -876,8 +1231,8 @@ def test_max_log_and_large_agent_event_use_bounded_live_and_hydration_transport( ] for update in operator._stream_history: - envelope_message = run_update_envelope_to_proto( - RunUpdateEnvelope( + envelope_message = operator_update_envelope_to_proto( + OperatorUpdateEnvelope( operator_instance_id=operator.operator_instance_id, update=update, ) diff --git a/test/operator_tests/test_web.py b/test/operator_tests/test_web.py new file mode 100644 index 0000000..d920322 --- /dev/null +++ b/test/operator_tests/test_web.py @@ -0,0 +1,152 @@ +"""Browser-compatible transport and asset serving tests.""" + +from __future__ import annotations + +import http.client +import struct +from pathlib import Path + +import pytest + +from runtime.operator.operator import Operator +from runtime.operator.proto import operator_pb2 as pb +from runtime.operator.web import start_browser_server + +_SERVICE = "/avalanche.operator.OperatorService/" +_CONTENT_TYPE = "application/grpc-web+proto" + + +def _frame(message) -> bytes: + payload = message.SerializeToString() + return struct.pack(">BI", 0, len(payload)) + payload + + +def _frames(body: bytes) -> list[tuple[int, bytes]]: + frames = [] + offset = 0 + while offset < len(body): + flags, length = struct.unpack(">BI", body[offset : offset + 5]) + offset += 5 + frames.append((flags, body[offset : offset + length])) + offset += length + assert offset == len(body) + return frames + + +def _post(server, method: str, request) -> tuple[int, str, bytes]: + connection = http.client.HTTPConnection(server.host, server.port, timeout=5) + body = _frame(request) + connection.request( + "POST", + f"{_SERVICE}{method}", + body=body, + headers={"Content-Type": _CONTENT_TYPE}, + ) + response = connection.getresponse() + result = response.status, response.getheader("Content-Type"), response.read() + connection.close() + return result + + +def test_browser_listener_serves_unary_catalog_from_shared_operator(tmp_path: Path): + (tmp_path / "index.html").write_text("
Avalanche
") + operator = Operator([], watch=False, schedule=False) + server = start_browser_server(operator, port=0, asset_root=tmp_path) + try: + status, content_type, body = _post(server, "GetCatalog", pb.Empty()) + frames = _frames(body) + catalog = pb.CatalogSnapshotMsg.FromString(frames[0][1]) + + assert status == 200 + assert content_type == _CONTENT_TYPE + assert catalog.operator_instance_id == operator.operator_instance_id + assert catalog.as_of_sequence == operator.current_sequence + assert frames[1][0] == 0x80 + assert b"grpc-status: 0" in frames[1][1] + finally: + server.close() + operator.close() + + +def test_browser_listener_delivers_stream_reset_as_grpc_web_frames(tmp_path: Path): + (tmp_path / "index.html").write_text("
Avalanche
") + operator = Operator([], watch=False, schedule=False) + server = start_browser_server(operator, port=0, asset_root=tmp_path) + try: + status, _, body = _post( + server, + "StreamOperatorUpdates", + pb.StreamOperatorUpdatesRequest( + operator_instance_id="stale-operator", + after_sequence=42, + ), + ) + frames = _frames(body) + envelope = pb.OperatorUpdateEnvelope.FromString(frames[0][1]) + + assert status == 200 + assert envelope.operator_instance_id == operator.operator_instance_id + assert envelope.HasField("reset_required") + assert frames[-1][0] == 0x80 + assert b"grpc-status: 0" in frames[-1][1] + finally: + server.close() + operator.close() + + +def test_browser_listener_serves_assets_and_spa_routes(tmp_path: Path): + (tmp_path / "index.html").write_text("
Avalanche
") + assets = tmp_path / "assets" + assets.mkdir() + (assets / "app.js").write_text("console.log('loaded')") + operator = Operator([], watch=False, schedule=False) + server = start_browser_server(operator, port=0, asset_root=tmp_path) + try: + connection = http.client.HTTPConnection(server.host, server.port, timeout=5) + connection.request("GET", "/runs/run-1") + response = connection.getresponse() + assert response.status == 200 + assert response.read() == b"
Avalanche
" + + connection.request("GET", "/assets/app.js") + response = connection.getresponse() + assert response.status == 200 + assert response.getheader("Content-Type") == "text/javascript" + assert response.read() == b"console.log('loaded')" + connection.close() + finally: + server.close() + operator.close() + + +def test_browser_listener_serves_packaged_operator_application(): + operator = Operator([], watch=False, schedule=False) + server = start_browser_server(operator, port=0) + try: + connection = http.client.HTTPConnection(server.host, server.port, timeout=5) + connection.request("GET", "/") + response = connection.getresponse() + body = response.read() + + assert response.status == 200 + assert response.getheader("Content-Type") == "text/html" + assert b"Avalanche Operator" in body + assert b'id="root"' in body + connection.close() + finally: + server.close() + operator.close() + + +def test_browser_listener_rejects_non_loopback_without_trusted_proxy(tmp_path: Path): + operator = Operator([], watch=False, schedule=False) + try: + with pytest.raises(ValueError, match="trusted, authenticated boundary"): + start_browser_server( + operator, + host="0.0.0.0", + port=0, + asset_root=tmp_path, + ) + finally: + operator.close() diff --git a/test/tui_test.py b/test/tui_test.py index 479dd6e..03645ce 100644 --- a/test/tui_test.py +++ b/test/tui_test.py @@ -50,6 +50,7 @@ MockStateProvider, ) from avalanche.tui.models import ( + CatalogSnapshot, LogEntry, LogLevel, NodeState, @@ -2106,7 +2107,7 @@ def close(self): generation=1, operator_instance_id="operator-1", as_of_sequence=2, - workflows=(workflow,), + catalog=CatalogSnapshot(workflows=(workflow,)), runs_by_workflow={workflow.selector: (reset_run,)}, ) ) @@ -2244,7 +2245,7 @@ def test_detail_retry_cancelled_by_navigation_reset_and_shutdown(self): generation=1, operator_instance_id="operator-2", as_of_sequence=2, - workflows=(workflow,), + catalog=CatalogSnapshot(workflows=(workflow,)), runs_by_workflow={workflow.selector: (reset_run,)}, ) ) @@ -2670,7 +2671,7 @@ def load_reset_baseline(self, notice): generation=notice.generation, operator_instance_id="operator-recovered", as_of_sequence=notice.observed_sequence, - workflows=(INGEST_WORKFLOW,), + catalog=CatalogSnapshot(workflows=(INGEST_WORKFLOW,)), runs_by_workflow={INGEST_WORKFLOW.selector: ()}, ) @@ -2726,14 +2727,14 @@ def load_reset_baseline(self, notice): generation=generation, operator_instance_id=operator_instance_id, as_of_sequence=as_of_sequence, - workflows=(), + catalog=CatalogSnapshot(workflows=()), runs_by_workflow={}, ) return ResetBaseline( generation=notice.generation, operator_instance_id=notice.operator_instance_id, as_of_sequence=notice.observed_sequence, - workflows=(INGEST_WORKFLOW,), + catalog=CatalogSnapshot(workflows=(INGEST_WORKFLOW,)), runs_by_workflow={INGEST_WORKFLOW.selector: ()}, ) @@ -2801,7 +2802,7 @@ def get_run(self, run_id): generation=1, operator_instance_id="operator-1", as_of_sequence=2, - workflows=(ORDER_WORKFLOW,), + catalog=CatalogSnapshot(workflows=(ORDER_WORKFLOW,)), runs_by_workflow={ORDER_WORKFLOW.selector: (authoritative,)}, ) ) @@ -2845,7 +2846,7 @@ def load_baseline(notice): generation=notice.generation, operator_instance_id="operator-restarted", as_of_sequence=notice.observed_sequence, - workflows=(ORDER_WORKFLOW,), + catalog=CatalogSnapshot(workflows=(ORDER_WORKFLOW,)), runs_by_workflow={ORDER_WORKFLOW.selector: ()}, ) @@ -3023,8 +3024,8 @@ class RestartedStub: def __init__(self): self.stream_calls = 0 - def ListFlows(self, request, **kwargs): # noqa: N802 - return pb.FlowList(flows=[workflow_info_to_proto(stale_workflow)]) + def GetCatalog(self, request, **kwargs): # noqa: N802 + return pb.CatalogSnapshotMsg(workflows=[workflow_info_to_proto(stale_workflow)]) def ListRunSummaries(self, request, **kwargs): # noqa: N802 return pb.RunSummaryPage( @@ -3032,7 +3033,7 @@ def ListRunSummaries(self, request, **kwargs): # noqa: N802 as_of_sequence=99, ) - def StreamRunUpdates(self, request, *, metadata): # noqa: N802 + def StreamOperatorUpdates(self, request, *, metadata): # noqa: N802 self.stream_calls += 1 assert metadata is None if self.stream_calls == 1: @@ -3040,7 +3041,7 @@ def StreamRunUpdates(self, request, *, metadata): # noqa: N802 assert request.after_sequence == 99 return iter( ( - pb.RunUpdateEnvelope( + pb.OperatorUpdateEnvelope( operator_instance_id="operator-restarted", reset_required=pb.ResetRequired( history_floor=1, @@ -3059,7 +3060,7 @@ def load_baseline(notice: StreamResetNotice) -> ResetBaseline: generation=notice.generation, operator_instance_id="operator-restarted", as_of_sequence=3, - workflows=(workflow,), + catalog=CatalogSnapshot(workflows=(workflow,)), runs_by_workflow={workflow.selector: (recovered,)}, ) @@ -3175,13 +3176,17 @@ def __init__( self.summary_tokens = [] self.snapshot_calls = [] - def ListFlows(self, request, context): # noqa: N802 - return pb.FlowList(flows=[workflow_info_to_proto(workflow)]) + def GetCatalog(self, request, context): # noqa: N802 + return pb.CatalogSnapshotMsg( + operator_instance_id=self.operator_id, + as_of_sequence=self.baseline_sequence, + workflows=[workflow_info_to_proto(workflow)], + ) - def StreamRunUpdates(self, request, context): # noqa: N802 + def StreamOperatorUpdates(self, request, context): # noqa: N802 context.send_initial_metadata(()) if request.operator_instance_id != self.operator_id: - yield pb.RunUpdateEnvelope( + yield pb.OperatorUpdateEnvelope( operator_instance_id=self.operator_id, reset_required=pb.ResetRequired( history_floor=1, diff --git a/web/operator/index.html b/web/operator/index.html new file mode 100644 index 0000000..f750942 --- /dev/null +++ b/web/operator/index.html @@ -0,0 +1,17 @@ + + + + + + + + + Avalanche Operator + + + +
+ + + + \ No newline at end of file diff --git a/web/operator/package.json b/web/operator/package.json new file mode 100644 index 0000000..2d3d7c9 --- /dev/null +++ b/web/operator/package.json @@ -0,0 +1,45 @@ +{ + "name": "@avalanche/operator-web", + "private": true, + "version": "0.1.0", + "type": "module", + "scripts": { + "build": "tsc --noEmit -p tsconfig.app.json && tsc --noEmit -p tsconfig.node.json && vite build", + "dev": "vite", + "generate": "uv run python -m grpc_tools.protoc -I../../src/runtime/operator/proto --plugin=protoc-gen-ts=./node_modules/.bin/protoc-gen-ts --ts_out=src/generated --ts_opt=long_type_string ../../src/runtime/operator/proto/operator.proto", + "benchmark": "pnpm run benchmark:unit && pnpm run benchmark:browser", + "benchmark:unit": "vitest run src/operator.large-run.benchmark.test.tsx --maxWorkers=1 --minWorkers=1 --no-file-parallelism", + "benchmark:browser": "node scripts/operator-large-run-browser-benchmark.mjs", + "test": "vitest run --maxWorkers=1 --minWorkers=1 --no-file-parallelism --exclude src/operator.large-run.benchmark.test.tsx" + }, + "dependencies": { + "@codemirror/lang-json": "^6.0.2", + "@codemirror/state": "^6.5.2", + "@codemirror/view": "^6.38.6", + "@protobuf-ts/grpcweb-transport": "^2.11.1", + "@protobuf-ts/runtime": "^2.11.1", + "@protobuf-ts/runtime-rpc": "^2.11.1", + "@tanstack/react-virtual": "^3.13.12", + "@xyflow/react": "^12.9.2", + "lucide-react": "^1.28.0", + "react": "^19.1.1", + "react-dom": "^19.1.1", + "react-markdown": "^10.1.0" + }, + "devDependencies": { + "@protobuf-ts/plugin": "^2.11.1", + "@tailwindcss/vite": "^4.3.3", + "@testing-library/jest-dom": "6.9.1", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", + "@types/react": "^19.1.16", + "@types/react-dom": "^19.1.9", + "@vitejs/plugin-react": "^5.0.4", + "jsdom": "^27.0.0", + "tailwindcss": "^4.3.3", + "typescript": "^5.9.2", + "vite": "^7.1.7", + "vitest": "^3.2.4" + }, + "packageManager": "pnpm@10.17.1" +} diff --git a/web/operator/pnpm-lock.yaml b/web/operator/pnpm-lock.yaml new file mode 100644 index 0000000..2c9bc31 --- /dev/null +++ b/web/operator/pnpm-lock.yaml @@ -0,0 +1,3398 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@codemirror/lang-json': + specifier: ^6.0.2 + version: 6.0.2 + '@codemirror/state': + specifier: ^6.5.2 + version: 6.7.1 + '@codemirror/view': + specifier: ^6.38.6 + version: 6.43.7 + '@protobuf-ts/grpcweb-transport': + specifier: ^2.11.1 + version: 2.11.1 + '@protobuf-ts/runtime': + specifier: ^2.11.1 + version: 2.11.1 + '@protobuf-ts/runtime-rpc': + specifier: ^2.11.1 + version: 2.11.1 + '@tanstack/react-virtual': + specifier: ^3.13.12 + version: 3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@xyflow/react': + specifier: ^12.9.2 + version: 12.11.2(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + lucide-react: + specifier: ^1.28.0 + version: 1.28.0(react@19.2.8) + react: + specifier: ^19.1.1 + version: 19.2.8 + react-dom: + specifier: ^19.1.1 + version: 19.2.8(react@19.2.8) + react-markdown: + specifier: ^10.1.0 + version: 10.1.0(@types/react@19.2.18)(react@19.2.8) + devDependencies: + '@protobuf-ts/plugin': + specifier: ^2.11.1 + version: 2.11.1 + '@tailwindcss/vite': + specifier: ^4.3.3 + version: 4.3.3(vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0)) + '@testing-library/jest-dom': + specifier: 6.9.1 + version: 6.9.1 + '@testing-library/react': + specifier: ^16.3.0 + version: 16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8) + '@testing-library/user-event': + specifier: ^14.6.1 + version: 14.6.1(@testing-library/dom@10.4.1) + '@types/react': + specifier: ^19.1.16 + version: 19.2.18 + '@types/react-dom': + specifier: ^19.1.9 + version: 19.2.4(@types/react@19.2.18) + '@vitejs/plugin-react': + specifier: ^5.0.4 + version: 5.2.0(vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0)) + jsdom: + specifier: ^27.0.0 + version: 27.4.0 + tailwindcss: + specifier: ^4.3.3 + version: 4.3.3 + typescript: + specifier: ^5.9.2 + version: 5.9.3 + vite: + specifier: ^7.1.7 + version: 7.3.6(jiti@2.7.0)(lightningcss@1.32.0) + vitest: + specifier: ^3.2.4 + version: 3.2.7(@types/debug@4.1.13)(jiti@2.7.0)(jsdom@27.4.0)(lightningcss@1.32.0) + +packages: + + '@acemir/cssom@0.9.31': + resolution: {integrity: sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA==} + + '@adobe/css-tools@4.5.0': + resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} + + '@asamuzakjp/css-color@4.1.2': + resolution: {integrity: sha512-NfBUvBaYgKIuq6E/RBLY1m0IohzNHAYyaJGuTK79Z23uNwmz2jl1mPsC5ZxCCxylinKhT1Amn5oNTlx1wN8cQg==} + + '@asamuzakjp/dom-selector@6.8.1': + resolution: {integrity: sha512-MvRz1nCqW0fsy8Qz4dnLIvhOlMzqDVBabZx6lH+YywFDdjXhMY37SmpV1XFX3JzG5GWHn63j6HX6QPr3lZXHvQ==} + + '@asamuzakjp/nwsapi@2.3.9': + resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.8': + resolution: {integrity: sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-transform-react-jsx-self@7.29.7': + resolution: {integrity: sha512-TL0hMc9xzy86VD31nUiwzd5otRAcyEPcsegCxolO0PvcXuH1v0kECe/UIznYFihpkvU5wg/jk4v0TTEFfm53fw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-transform-react-jsx-source@7.29.7': + resolution: {integrity: sha512-06IyK09H3wi4cGbhDBwp5gUGo0IKtnYa8tyTiephirPCK6fbobVGiXMMI5zLQ4aKEYP3wZ3ArU44o+8KMrSG/Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} + engines: {node: '>=6.9.0'} + + '@bufbuild/protobuf@2.13.0': + resolution: {integrity: sha512-acq7c49vxfm1ggJ95P70TX7ABDM0vxr1SYD3BB0o0jnBLB4OAqeHyKuN+cD3w80gXEDQ2zxHpR6CUeA+O/aU9g==} + + '@bufbuild/protoplugin@2.13.0': + resolution: {integrity: sha512-32eMChKaL/A8Hh5AfMmXSdnuyznN85uoEjoyWiWeRrvtQOtpqX/v1R9PDe0g9vMIgzznK9inMT3CUaal0kjLUQ==} + + '@codemirror/lang-json@6.0.2': + resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} + + '@codemirror/language@6.12.4': + resolution: {integrity: sha512-1q4PaT+o6PbgpkJt4Q8Fv5XJxTy4FUZ4MWETtyiDw3J0Pyr9E2vqcKL+k9wcvjNTIsauxvE7OfmWj3FRPHQ76A==} + + '@codemirror/state@6.7.1': + resolution: {integrity: sha512-9QzNDgE4EYDnAHfrTlR2lwiPciiOymLtwKK+8yHQzCc7GXhAP9xdEbEJFy2IWB1j9UGUl9BsgMmTo/ImA02T7A==} + + '@codemirror/view@6.43.7': + resolution: {integrity: sha512-FZsExxkoxnAN+d9TgqXLg5g4A1oQwzX9WlkOT5i2PKkcW7xx3Bmu0vs90g6fo9Mpdsb/l96dnAraQ8932aO4/g==} + + '@csstools/color-helpers@6.1.0': + resolution: {integrity: sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==} + engines: {node: '>=20.19.0'} + + '@csstools/css-calc@3.3.0': + resolution: {integrity: sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-color-parser@4.1.10': + resolution: {integrity: sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} + peerDependencies: + '@csstools/css-tokenizer': ^4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.7': + resolution: {integrity: sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true + + '@csstools/css-tokenizer@4.0.0': + resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + engines: {node: '>=20.19.0'} + + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + 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 + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@lezer/common@1.5.2': + resolution: {integrity: sha512-sxQE460fPZyU3sdc8lafxiPwJHBzZRy/udNFynGQky1SePYBdhkBl1kOagA9uT3pxR8K09bOrmTUqA9wb/PjSQ==} + + '@lezer/highlight@1.2.3': + resolution: {integrity: sha512-qXdH7UqTvGfdVBINrgKhDsVTJTxactNNxLk7+UMwZhU13lMHaOBlJe9Vqp907ya56Y3+ed2tlqzys7jDkTmW0g==} + + '@lezer/json@1.0.3': + resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} + + '@lezer/lr@1.4.10': + resolution: {integrity: sha512-rnCpTIBafOx4mRp43xOxDJbFipJm/c0cia/V5TiGlhmMa+wsSdoGmUN3w5Bqrks/09Q/D4tNAmWaT8p6NRi77A==} + + '@marijn/find-cluster-break@1.0.3': + resolution: {integrity: sha512-FY+MKLBoTsLNJF/eLWaOsXGdz6uh3Iu1axjPf6TUq92IYumcTcXWHoS747JARLkcdlJ/Waiaxc5wQfFO8jC6NA==} + + '@protobuf-ts/grpcweb-transport@2.11.1': + resolution: {integrity: sha512-1W4utDdvOB+RHMFQ0soL4JdnxjXV+ddeGIUg08DvZrA8Ms6k5NN6GBFU2oHZdTOcJVpPrDJ02RJlqtaoCMNBtw==} + + '@protobuf-ts/plugin@2.11.1': + resolution: {integrity: sha512-HyuprDcw0bEEJqkOWe1rnXUP0gwYLij8YhPuZyZk6cJbIgc/Q0IFgoHQxOXNIXAcXM4Sbehh6kjVnCzasElw1A==} + hasBin: true + + '@protobuf-ts/protoc@2.11.1': + resolution: {integrity: sha512-mUZJaV0daGO6HUX90o/atzQ6A7bbN2RSuHtdwo8SSF2Qoe3zHwa4IHyCN1evftTeHfLmdz+45qo47sL+5P8nyg==} + hasBin: true + + '@protobuf-ts/runtime-rpc@2.11.1': + resolution: {integrity: sha512-4CqqUmNA+/uMz00+d3CYKgElXO9VrEbucjnBFEjqI4GuDrEQ32MaI3q+9qPBvIGOlL4PmHXrzM32vBPWRhQKWQ==} + + '@protobuf-ts/runtime@2.11.1': + resolution: {integrity: sha512-KuDaT1IfHkugM2pyz+FwiY80ejWrkH1pAtOBOZFuR6SXEFTsnb/jiQWQ1rCIrcKx2BtyxnxW6BWwsVSA/Ie+WQ==} + + '@rolldown/pluginutils@1.0.0-rc.3': + resolution: {integrity: sha512-eybk3TjzzzV97Dlj5c+XrBFW57eTNhzod66y9HrBlzJ6NsCrWCp/2kaPS3K9wJmurBC0Tdw4yPjXKZqlznim3Q==} + + '@rollup/rollup-android-arm-eabi@4.62.3': + resolution: {integrity: sha512-c0wdcekXtQvvn5Tsrk/+op/gUArrbWaFduBnTLP2l1cKLSQs4diMWjJw3m6A0DdzT8dAAX95KpkJ3qynCePbmw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.62.3': + resolution: {integrity: sha512-3YjElDdWN+qXAFbJ/CzPV+0wspLqh54k/I6GfdYtEJRqg7buSgc1yPM3B+93j1M4neobtkATHZTmxK2AMVGfnA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.62.3': + resolution: {integrity: sha512-Pch2pFNOxxz1hTjypIdPyRTR6riiwRl84+VcN9djS680fw+Co1nAJINrdpqp7KV0NvyuU8ilZXZCjd7ykJl1GQ==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.62.3': + resolution: {integrity: sha512-LEuncFUHFiF8t4yZVZvvZA1wk0pjAscRnsrn1EfTEmN4HXotBi2YtcnLRyaK6UbuczW7xZS5ES+81Rdz8Z0T6g==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.62.3': + resolution: {integrity: sha512-zvBUvsQUpOWALdDsk6qbS8bXf2VxmPisuudNDrY7x0p0jBdsoZl8HsHczIOgkQiZldmcacMKtBzpoGVNeIe2bQ==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.62.3': + resolution: {integrity: sha512-C2KmNrcSem/AMg984H/dev+si0lieQGdXdR/lYGJnuumXnFb9Y7QdiI62obFdLlxRYLBv4P0eUVIDbD4c1vVvw==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.62.3': + resolution: {integrity: sha512-ggXnsTAEzNQx74XpunRsiZ9aBZDsI7XIa0hm2nzR9f4WzH5/f/d73ZSDaC5ejJ8YLY4NW+V3wr0tjOaeCq8hqA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.62.3': + resolution: {integrity: sha512-2vng+FlzNUhKZxtej3IUqJgbZoQk2M/dwQM20+ULV0R/E/8tr9/P6uEf2iiGIk4HL0zMKh5Jry7mUHdUOvyGgA==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.62.3': + resolution: {integrity: sha512-LLLFZKt4/Nraf9rxDkhiU8QVgLF4WmCkfr0L4fj0fPfIZFBib0DeiFk1hhaYKd03LFAFJcxHslhDFlNJLylf5Q==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.62.3': + resolution: {integrity: sha512-WJkdQCvS9sWNOUBJZfQRKpZGFBztRzcowI+nndmflKgU4XY+3a420FgTOSKTsVqJbnzSxeT4vaJalpOaPo2YCQ==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.62.3': + resolution: {integrity: sha512-PwHXCCS2n64/1Ot6rP1YEYA02MGYBcQlr8CSZZyrUG2O7NH6NklYmvr9v3Jy+5e/eDeNchc/ukmKJi9LuflMIQ==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.62.3': + resolution: {integrity: sha512-vUjxINQu3RC8NZS3ykk1gN65gIz8pAopOq2HXuZhiIxHdx7TFvDG+jgrdSgInu1Eza4/Rfi2VzZgyIgEH4WOaw==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.62.3': + resolution: {integrity: sha512-wzko4aJ13+0G3kGnviCg5gnXFKd40izKsrf2uOw12US4XqprkDrmwOpeW14aSNa37V8bfPcz5Fkob6LZ3BAPmA==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.62.3': + resolution: {integrity: sha512-8120ue0JUMSwy11stlwnfdX3pPd+WZYGCDBwEHWtIHi6pOpZmsEF5QKB7a/UN+XFdqvobxz98kv8RTqikyCEBw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.62.3': + resolution: {integrity: sha512-XLFHnR3tXMjbOCh2vtVJHmxt+995uJsTERQyseFDRA0xxMxyTZPLa3OIUlyFaO4mF/Lu0FjmWHCuPXJT1n/IOg==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.62.3': + resolution: {integrity: sha512-se6yXvNGMIl0f+RQzyh7XAmia8/9kplQx424wnG2w0C1oi6XgO6Y8otKhdXFHbHs88Ihavzmvh1NWjuovE76BQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.62.3': + resolution: {integrity: sha512-gNoxRefktVIiGflpONuxWWXZAzIQG++z9qHO3xKwk4WdDMuQja3JHGfE1u0i3PfPDyvhypdk+WrgIJqLhGG7sg==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.62.3': + resolution: {integrity: sha512-V4KtWtQfAFMU7+9/A/VDps/VI8CHd3cYz0L8sgJzz8qK7eY7wI4ruFD82UYIYvW9Z4DtlTfhQcsl4XyPHW5uSg==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.62.3': + resolution: {integrity: sha512-LBx9LYXvj2CBkMkjLdNAWLwH0MLMin7do2VcVo9kVPibGLkY0BQQut2fv7NVqkXqZ/CrAu9LqDHVV1xHCMpCPw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.62.3': + resolution: {integrity: sha512-ABVf3Q0RCu7NcyCCOZQI0pJ3GuSdfSl8EXcy88QtdceIMIoCUdfhsJChZ64L9zVM2aJHjde1Bhn5uqSRcX9ySA==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.62.3': + resolution: {integrity: sha512-+2Cy/ldweGBLlPIKsQLF8U5N44a0KDdbrk1rAjHOM9M2K+kGdIVjHLmmrZIcx+9Ny3ke/1JomCsDI1ocb11+sg==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.62.3': + resolution: {integrity: sha512-dtZvzc8BedpSaFNy75x6uiWwAGTH+aZHDtdrqP6qk+WcLJrfti6sGje1ZJ9UxyzDLF23d/mV+PaMwuC0hL7UVA==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.62.3': + resolution: {integrity: sha512-Rj8Ra4noo+aYy7sKBggCx0407mws34kAb1ySyWuq5DAtFBQdkSwnsjCgPrhPe9cvgBKZIukpE+CVHvORCS93kQ==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.62.3': + resolution: {integrity: sha512-vp7N084ew/odXn2gi/mzm9mUkQu9l6AiN6dt4IeUM2Uvm9o+cVmP+YkqbMOteLbiGgqBBlJZjIMYVCfOOIVbVQ==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.62.3': + resolution: {integrity: sha512-MOG/3gTOn4Fwf574RVOaY61I5o6P90legkFADiTyn1hyjNydT+cerU2rLUwPdZkKKyJ+iT+K9p7WXK4LM1Ka6g==} + cpu: [x64] + os: [win32] + + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} + + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} + engines: {node: '>= 20'} + + '@tailwindcss/vite@4.3.3': + resolution: {integrity: sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==} + peerDependencies: + vite: ^5.2.0 || ^6 || ^7 || ^8 + + '@tanstack/react-virtual@3.14.9': + resolution: {integrity: sha512-qZyr0FZDP8rDC4WBhsryIZmAd9bveJvFGUJJtskWaew6/0dTRS6wZxnR6VQ5bY2KwL3LjerrHqQLk3a0GKcPXQ==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + '@tanstack/virtual-core@3.17.7': + resolution: {integrity: sha512-bp+v10y65sp2H7WpWfIMyxTNfl8ZVfxFTLRjPIFRryi6FV/J33z4IS53WO4pTk36KlvJ4iLiQz+oaydDC1xbcA==} + + '@testing-library/dom@10.4.1': + resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + engines: {node: '>=18'} + + '@testing-library/jest-dom@6.9.1': + resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} + engines: {node: '>=14', npm: '>=6', yarn: '>=1'} + + '@testing-library/react@16.3.2': + resolution: {integrity: sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==} + engines: {node: '>=18'} + peerDependencies: + '@testing-library/dom': ^10.0.0 + '@types/react': ^18.0.0 || ^19.0.0 + '@types/react-dom': ^18.0.0 || ^19.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@testing-library/user-event@14.6.1': + resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + engines: {node: '>=12', npm: '>=6'} + peerDependencies: + '@testing-library/dom': '>=7.21.4' + + '@types/aria-query@5.0.4': + resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/chai@5.2.3': + resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} + + '@types/d3-color@3.1.3': + resolution: {integrity: sha512-iO90scth9WAbmgv7ogoq57O9YpKmFBbmoEoCHDB2xMBY0+/KVrqAaCDyCE16dUspeOvIxFFRI+0sEtqDqy2b4A==} + + '@types/d3-drag@3.0.7': + resolution: {integrity: sha512-HE3jVKlzU9AaMazNufooRJ5ZpWmLIoc90A37WU2JMmeq28w1FQqCZswHZ3xR+SuxYftzHq6WU6KJHvqxKzTxxQ==} + + '@types/d3-interpolate@3.0.4': + resolution: {integrity: sha512-mgLPETlrpVV1YRJIglr4Ez47g7Yxjl1lj7YKsiMCb27VJH9W8NVM6Bb9d8kkpG/uAQS5AmbA48q2IAolKKo1MA==} + + '@types/d3-selection@3.0.11': + resolution: {integrity: sha512-bhAXu23DJWsrI45xafYpkQ4NtcKMwWnAC/vKrd2l+nxMFuvOT3XMYTIj2opv8vq8AO5Yh7Qac/nSeP/3zjTK0w==} + + '@types/d3-transition@3.0.9': + resolution: {integrity: sha512-uZS5shfxzO3rGlu0cC3bjmMFKsXv+SmZZcgp0KD22ts4uGXp5EVYGzu/0YdwZeKmddhcAccYtREJKkPfXkZuCg==} + + '@types/d3-zoom@3.0.8': + resolution: {integrity: sha512-iqMC4/YlFCSlO8+2Ii1GGGliCAY4XdeG748w5vQUbevlbDu0zSjH/+jojorQVBK/se0j6DUFNPBGSqD3YWYnDw==} + + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} + + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + + '@types/estree-jsx@1.0.5': + resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.5': + resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + + '@types/react-dom@19.2.4': + resolution: {integrity: sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.18': + resolution: {integrity: sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==} + + '@types/unist@2.0.11': + resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@typescript/vfs@1.6.4': + resolution: {integrity: sha512-PJFXFS4ZJKiJ9Qiuix6Dz/OwEIqHD7Dme1UwZhTK11vR+5dqW2ACbdndWQexBzCx+CPuMe5WBYQWCsFyGlQLlQ==} + peerDependencies: + typescript: '*' + + '@ungap/structured-clone@1.3.3': + resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} + + '@vitejs/plugin-react@5.2.0': + resolution: {integrity: sha512-YmKkfhOAi3wsB1PhJq5Scj3GXMn3WvtQ/JC0xoopuHoXSdmtdStOpFrYaT1kie2YgFBcIe64ROzMYRjCrYOdYw==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@vitest/expect@3.2.7': + resolution: {integrity: sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w==} + + '@vitest/mocker@3.2.7': + resolution: {integrity: sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true + + '@vitest/pretty-format@3.2.7': + resolution: {integrity: sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA==} + + '@vitest/runner@3.2.7': + resolution: {integrity: sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA==} + + '@vitest/snapshot@3.2.7': + resolution: {integrity: sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g==} + + '@vitest/spy@3.2.7': + resolution: {integrity: sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ==} + + '@vitest/utils@3.2.7': + resolution: {integrity: sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw==} + + '@xyflow/react@12.11.2': + resolution: {integrity: sha512-eLAlDWJfWnQEhJwGMjlWdAXO9eYllKpliUmPQlAmOLxz6mExXuzMVDUKLMquixgkrtmMFFtug3jGKmYYld12cA==} + peerDependencies: + '@types/react': '>=17' + '@types/react-dom': '>=17' + react: '>=17' + react-dom: '>=17' + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@xyflow/system@0.0.79': + resolution: {integrity: sha512-czLyOh91NF0hIzbNzwi8I6GlqG23BHh2435OddfI6uiaLH3xdrdygO93gqgH1Bv9mhy8XPFQJOBn1FTq4LvEWA==} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + aria-query@5.3.0: + resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} + + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} + + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} + + bail@2.0.2: + resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} + + baseline-browser-mapping@2.11.9: + resolution: {integrity: sha512-cp447VUsGS07+n1Dqf7YSQ8maeJrjEhaDxTm1ZefbqDtypHBC5GzGMQbklR6IPR13Y8OAJRHZWEMtZipJLCttg==} + engines: {node: '>=6.0.0'} + hasBin: true + + bidi-js@1.0.3: + resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + + browserslist@4.28.7: + resolution: {integrity: sha512-JxV13hNrFxqjOc8alRbq9dK1MM79NEXYpma2B2J4wAtpWS5zIEIKqWPGCl7N4o7Uc7B7itylh7SuDujATRyyTw==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + caniuse-lite@1.0.30001806: + resolution: {integrity: sha512-72Cuvd95zbSYPKq6Fhg8eDJRlzgWDf7/mtoZv6Qe/DYNCEBdNxoA3+rZAU2ZhGCpZlns3EssFavaZomckT5Uuw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chai@5.3.3: + resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} + engines: {node: '>=18'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + character-entities@2.0.2: + resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} + + character-reference-invalid@2.0.1: + resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} + + check-error@2.1.3: + resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} + engines: {node: '>= 16'} + + classcat@5.0.5: + resolution: {integrity: sha512-JhZUT7JFcQy/EzW605k/ktHtncoo9vnyW/2GspNYwFlN1C/WmjuV/xtS04e9SOkL2sTdw0VAZ2UGCcQ9lR6p6w==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + crelt@1.0.7: + resolution: {integrity: sha512-aK6BbWfhf4U/wCcLHKPJl/xa6VkVstRaPywWtMKGwuOLc/wZTyQYuoxgvZnNsBvv7Kg3YTBQYYBCggcviQczuA==} + + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} + engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + + css.escape@1.5.1: + resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} + + cssstyle@5.3.7: + resolution: {integrity: sha512-7D2EPVltRrsTkhpQmksIu+LxeWAIEk6wRDMJ1qljlv+CKHJM+cJLlfhWIzNA44eAsHXSNe3+vO6DW1yCYx8SuQ==} + engines: {node: '>=20'} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + d3-color@3.1.0: + resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} + engines: {node: '>=12'} + + d3-dispatch@3.0.1: + resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} + engines: {node: '>=12'} + + d3-drag@3.0.0: + resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} + engines: {node: '>=12'} + + d3-ease@3.0.1: + resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} + engines: {node: '>=12'} + + d3-interpolate@3.0.1: + resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} + engines: {node: '>=12'} + + d3-selection@3.0.0: + resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} + engines: {node: '>=12'} + + d3-timer@3.0.1: + resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} + engines: {node: '>=12'} + + d3-transition@3.0.1: + resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} + engines: {node: '>=12'} + peerDependencies: + d3-selection: 2 - 3 + + d3-zoom@3.0.0: + resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} + engines: {node: '>=12'} + + data-urls@6.0.1: + resolution: {integrity: sha512-euIQENZg6x8mj3fO6o9+fOW8MimUI4PpD/fZBhJfeioZVy9TUpM4UY7KjQNVZFlqwJ0UdzRDzkycB997HEq1BQ==} + engines: {node: '>=20'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} + + decode-named-character-reference@1.3.0: + resolution: {integrity: sha512-GtpQYB283KrPp6nRw50q3U9/VfOutZOe103qlN7BPP6Ad27xYnOIWv4lPzo8HCAL+mMZofJ9KEy30fq6MfaK6Q==} + + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dom-accessibility-api@0.5.16: + resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} + + dom-accessibility-api@0.6.3: + resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} + + electron-to-chromium@1.5.399: + resolution: {integrity: sha512-lEcqhErbHjXRvd41rnWLpzbyU/IXfIYo7QwaFWmxGeLiLyY2TBCdHnWY88vB+p3ubnihRypDm66panXl7TylLA==} + + enhanced-resolve@5.24.5: + resolution: {integrity: sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==} + engines: {node: '>=10.13.0'} + + entities@8.0.0: + resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} + engines: {node: '>=20.19.0'} + + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + estree-util-is-identifier-name@3.0.0: + resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} + + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} + engines: {node: '>=12.0.0'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + hast-util-to-jsx-runtime@2.3.6: + resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + html-url-attributes@3.0.1: + resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} + + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + indent-string@4.0.0: + resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} + engines: {node: '>=8'} + + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + + is-alphabetical@2.0.1: + resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} + + is-alphanumerical@2.0.1: + resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} + + is-decimal@2.0.1: + resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} + + is-hexadecimal@2.0.1: + resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} + + is-plain-obj@4.1.0: + resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} + engines: {node: '>=12'} + + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + + jsdom@27.4.0: + resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + canvas: ^3.0.0 + peerDependenciesMeta: + canvas: + optional: true + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + longest-streak@3.1.0: + resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} + + loupe@3.2.1: + resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} + + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@1.28.0: + resolution: {integrity: sha512-fARAFJULsGuDDydjp6+6blekG/sBIM29TerzLjc9bQUKAcEfrSc4ZQKb25KRz4OMKd87cZTb5dgq0w/T6KufVg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + lz-string@1.5.0: + resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} + hasBin: true + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + mdast-util-from-markdown@2.0.3: + resolution: {integrity: sha512-W4mAWTvSlKvf8L6J+VN9yLSqQ9AOAAvHuoDAmPkz4dHf553m5gVj2ejadHJhoJmcmxEnOv6Pa8XJhpxE93kb8Q==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + min-indent@1.0.1: + resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} + engines: {node: '>=4'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.16: + resolution: {integrity: sha512-bzlKTyNJ7+LdGIIwy8ijFpIqEQIvafahV7eYykJ8Cvh42EdJeODoJ6gUJXpQJvej1BddH8OqTXZNE/KfbWAu8Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + node-releases@2.0.51: + resolution: {integrity: sha512-wRNIrw4DmVLKQlbgOMdkMx27Wrpzes2hh5Jtbi2bjPd+4wJstWIqP5A+lscnqbm0xxmT5Bpg8Lec5ItEBwx6BQ==} + engines: {node: '>=18'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.5: + resolution: {integrity: sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==} + engines: {node: '>=12'} + + postcss@8.5.25: + resolution: {integrity: sha512-DTPx3RWSSnWyzLxQnlH0rJP+EW5ekl16ZU4/psbIhA0e53kJfdgaN5vKM+xP7yJtXVu+nfdVFmlgFDEKAe4Pyw==} + engines: {node: ^10 || ^12 || >=14} + + pretty-format@27.5.1: + resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} + engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} + peerDependencies: + react: ^19.2.8 + + react-is@17.0.2: + resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} + + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react@19.2.8: + resolution: {integrity: sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==} + engines: {node: '>=0.10.0'} + + redent@3.0.0: + resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} + engines: {node: '>=8'} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + rollup@4.62.3: + resolution: {integrity: sha512-Gu0c0iH9FzgX1L1t7ByIbbS3Vmdz+6KHm/EsqmmC71gUQ82yvZRkTK6XzrFObSka91WUVdynqp6nsfilzr5k6Q==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-indent@3.0.0: + resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} + engines: {node: '>=8'} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + style-mod@4.1.3: + resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + tldts-core@7.4.10: + resolution: {integrity: sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==} + + tldts@7.4.10: + resolution: {integrity: sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==} + hasBin: true + + tough-cookie@6.0.2: + resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} + engines: {node: '>=16'} + + tr46@6.0.0: + resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} + engines: {node: '>=20'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + typescript@3.9.10: + resolution: {integrity: sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q==} + engines: {node: '>=4.2.0'} + hasBin: true + + typescript@5.4.5: + resolution: {integrity: sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==} + engines: {node: '>=14.17'} + hasBin: true + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@7.3.6: + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.7: + resolution: {integrity: sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.7 + '@vitest/ui': 3.2.7 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + w3c-keyname@2.2.8: + resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} + + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} + + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} + engines: {node: '>=20'} + + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} + + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} + engines: {node: '>=20'} + + whatwg-url@15.1.0: + resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + engines: {node: '>=20'} + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + ws@8.21.1: + resolution: {integrity: sha512-+0NTnW77fFN/DjQi6k/Sq/Yvk4Sgajw7urW8V+asjXnRgDs9gyGkdb7EzgfhA4goXsRIZKE28fzIXBHEzhuiWw==} + 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 + + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} + + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + zustand@4.5.7: + resolution: {integrity: sha512-CHOUy7mu3lbD6o6LJLfllpjkzhHXSBlX8B9+qPddUsIfeF5S/UZ5q0kmCsnRqT1UHFQZchNFDDzMbQsuesHWlw==} + engines: {node: '>=12.7.0'} + peerDependencies: + '@types/react': '>=16.8' + immer: '>=9.0.6' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@acemir/cssom@0.9.31': {} + + '@adobe/css-tools@4.5.0': {} + + '@asamuzakjp/css-color@4.1.2': + dependencies: + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-color-parser': 4.1.10(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + lru-cache: 11.5.2 + + '@asamuzakjp/dom-selector@6.8.1': + dependencies: + '@asamuzakjp/nwsapi': 2.3.9 + bidi-js: 1.0.3 + css-tree: 3.2.1 + is-potential-custom-element-name: 1.0.1 + lru-cache: 11.5.2 + + '@asamuzakjp/nwsapi@2.3.9': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.8': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.7 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.8 + '@babel/types': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + + '@babel/parser@7.29.8': + dependencies: + '@babel/types': 7.29.8 + + '@babel/plugin-transform-react-jsx-self@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-react-jsx-source@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/runtime@7.29.7': {} + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@babel/traverse@7.29.8': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.8 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.8': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@bufbuild/protobuf@2.13.0': {} + + '@bufbuild/protoplugin@2.13.0': + dependencies: + '@bufbuild/protobuf': 2.13.0 + '@typescript/vfs': 1.6.4(typescript@5.4.5) + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + + '@codemirror/lang-json@6.0.2': + dependencies: + '@codemirror/language': 6.12.4 + '@lezer/json': 1.0.3 + + '@codemirror/language@6.12.4': + dependencies: + '@codemirror/state': 6.7.1 + '@codemirror/view': 6.43.7 + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + style-mod: 4.1.3 + + '@codemirror/state@6.7.1': + dependencies: + '@marijn/find-cluster-break': 1.0.3 + + '@codemirror/view@6.43.7': + dependencies: + '@codemirror/state': 6.7.1 + crelt: 1.0.7 + style-mod: 4.1.3 + w3c-keyname: 2.2.8 + + '@csstools/color-helpers@6.1.0': {} + + '@csstools/css-calc@3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-color-parser@4.1.10(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/color-helpers': 6.1.0 + '@csstools/css-calc': 3.3.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + dependencies: + '@csstools/css-tokenizer': 4.0.0 + + '@csstools/css-syntax-patches-for-csstree@1.1.7(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 + + '@csstools/css-tokenizer@4.0.0': {} + + '@esbuild/aix-ppc64@0.28.1': + optional: true + + '@esbuild/android-arm64@0.28.1': + optional: true + + '@esbuild/android-arm@0.28.1': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.28.1': + optional: true + + '@esbuild/darwin-x64@0.28.1': + optional: true + + '@esbuild/freebsd-arm64@0.28.1': + optional: true + + '@esbuild/freebsd-x64@0.28.1': + optional: true + + '@esbuild/linux-arm64@0.28.1': + optional: true + + '@esbuild/linux-arm@0.28.1': + optional: true + + '@esbuild/linux-ia32@0.28.1': + optional: true + + '@esbuild/linux-loong64@0.28.1': + optional: true + + '@esbuild/linux-mips64el@0.28.1': + optional: true + + '@esbuild/linux-ppc64@0.28.1': + optional: true + + '@esbuild/linux-riscv64@0.28.1': + optional: true + + '@esbuild/linux-s390x@0.28.1': + optional: true + + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + + '@exodus/bytes@1.15.1': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@lezer/common@1.5.2': {} + + '@lezer/highlight@1.2.3': + dependencies: + '@lezer/common': 1.5.2 + + '@lezer/json@1.0.3': + dependencies: + '@lezer/common': 1.5.2 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.10 + + '@lezer/lr@1.4.10': + dependencies: + '@lezer/common': 1.5.2 + + '@marijn/find-cluster-break@1.0.3': {} + + '@protobuf-ts/grpcweb-transport@2.11.1': + dependencies: + '@protobuf-ts/runtime': 2.11.1 + '@protobuf-ts/runtime-rpc': 2.11.1 + + '@protobuf-ts/plugin@2.11.1': + dependencies: + '@bufbuild/protobuf': 2.13.0 + '@bufbuild/protoplugin': 2.13.0 + '@protobuf-ts/protoc': 2.11.1 + '@protobuf-ts/runtime': 2.11.1 + '@protobuf-ts/runtime-rpc': 2.11.1 + typescript: 3.9.10 + transitivePeerDependencies: + - supports-color + + '@protobuf-ts/protoc@2.11.1': {} + + '@protobuf-ts/runtime-rpc@2.11.1': + dependencies: + '@protobuf-ts/runtime': 2.11.1 + + '@protobuf-ts/runtime@2.11.1': {} + + '@rolldown/pluginutils@1.0.0-rc.3': {} + + '@rollup/rollup-android-arm-eabi@4.62.3': + optional: true + + '@rollup/rollup-android-arm64@4.62.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.62.3': + optional: true + + '@rollup/rollup-darwin-x64@4.62.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.62.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.62.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.62.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.62.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.62.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.62.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.62.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.62.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.62.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.62.3': + optional: true + + '@rollup/rollup-openbsd-x64@4.62.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.62.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.62.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.62.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.62.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.62.3': + optional: true + + '@tailwindcss/node@4.3.3': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.24.5 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.3 + + '@tailwindcss/oxide-android-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.3': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + optional: true + + '@tailwindcss/oxide@4.3.3': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 + + '@tailwindcss/vite@4.3.3(vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0))': + dependencies: + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + tailwindcss: 4.3.3 + vite: 7.3.6(jiti@2.7.0)(lightningcss@1.32.0) + + '@tanstack/react-virtual@3.14.9(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + dependencies: + '@tanstack/virtual-core': 3.17.7 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + + '@tanstack/virtual-core@3.17.7': {} + + '@testing-library/dom@10.4.1': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/runtime': 7.29.7 + '@types/aria-query': 5.0.4 + aria-query: 5.3.0 + dom-accessibility-api: 0.5.16 + lz-string: 1.5.0 + picocolors: 1.1.1 + pretty-format: 27.5.1 + + '@testing-library/jest-dom@6.9.1': + dependencies: + '@adobe/css-tools': 4.5.0 + aria-query: 5.3.2 + css.escape: 1.5.1 + dom-accessibility-api: 0.6.3 + picocolors: 1.1.1 + redent: 3.0.0 + + '@testing-library/react@16.3.2(@testing-library/dom@10.4.1)(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + dependencies: + '@babel/runtime': 7.29.7 + '@testing-library/dom': 10.4.1 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) + + '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + dependencies: + '@testing-library/dom': 10.4.1 + + '@types/aria-query@5.0.4': {} + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.8 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.8 + '@babel/types': 7.29.8 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.8 + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/d3-color@3.1.3': {} + + '@types/d3-drag@3.0.7': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-interpolate@3.0.4': + dependencies: + '@types/d3-color': 3.1.3 + + '@types/d3-selection@3.0.11': {} + + '@types/d3-transition@3.0.9': + dependencies: + '@types/d3-selection': 3.0.11 + + '@types/d3-zoom@3.0.8': + dependencies: + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + + '@types/debug@4.1.13': + dependencies: + '@types/ms': 2.1.0 + + '@types/deep-eql@4.0.2': {} + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.9 + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/react-dom@19.2.4(@types/react@19.2.18)': + dependencies: + '@types/react': 19.2.18 + + '@types/react@19.2.18': + dependencies: + csstype: 3.2.3 + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@typescript/vfs@1.6.4(typescript@5.4.5)': + dependencies: + debug: 4.4.3 + typescript: 5.4.5 + transitivePeerDependencies: + - supports-color + + '@ungap/structured-clone@1.3.3': {} + + '@vitejs/plugin-react@5.2.0(vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0))': + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-transform-react-jsx-self': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-transform-react-jsx-source': 7.29.7(@babel/core@7.29.7) + '@rolldown/pluginutils': 1.0.0-rc.3 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.3.6(jiti@2.7.0)(lightningcss@1.32.0) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@3.2.7': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.7(vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0))': + dependencies: + '@vitest/spy': 3.2.7 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.3.6(jiti@2.7.0)(lightningcss@1.32.0) + + '@vitest/pretty-format@3.2.7': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.7': + dependencies: + '@vitest/utils': 3.2.7 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.7': + dependencies: + tinyspy: 4.0.4 + + '@vitest/utils@3.2.7': + dependencies: + '@vitest/pretty-format': 3.2.7 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + '@xyflow/react@12.11.2(@types/react-dom@19.2.4(@types/react@19.2.18))(@types/react@19.2.18)(react-dom@19.2.8(react@19.2.8))(react@19.2.8)': + dependencies: + '@xyflow/system': 0.0.79 + classcat: 5.0.5 + react: 19.2.8 + react-dom: 19.2.8(react@19.2.8) + zustand: 4.5.7(@types/react@19.2.18)(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.18 + '@types/react-dom': 19.2.4(@types/react@19.2.18) + transitivePeerDependencies: + - immer + + '@xyflow/system@0.0.79': + dependencies: + '@types/d3-drag': 3.0.7 + '@types/d3-interpolate': 3.0.4 + '@types/d3-selection': 3.0.11 + '@types/d3-transition': 3.0.9 + '@types/d3-zoom': 3.0.8 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-zoom: 3.0.0 + + agent-base@7.1.4: {} + + ansi-regex@5.0.1: {} + + ansi-styles@5.2.0: {} + + aria-query@5.3.0: + dependencies: + dequal: 2.0.3 + + aria-query@5.3.2: {} + + assertion-error@2.0.1: {} + + bail@2.0.2: {} + + baseline-browser-mapping@2.11.9: {} + + bidi-js@1.0.3: + dependencies: + require-from-string: 2.0.2 + + browserslist@4.28.7: + dependencies: + baseline-browser-mapping: 2.11.9 + caniuse-lite: 1.0.30001806 + electron-to-chromium: 1.5.399 + node-releases: 2.0.51 + update-browserslist-db: 1.2.3(browserslist@4.28.7) + + cac@6.7.14: {} + + caniuse-lite@1.0.30001806: {} + + ccount@2.0.1: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.3 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + check-error@2.1.3: {} + + classcat@5.0.5: {} + + comma-separated-tokens@2.0.3: {} + + convert-source-map@2.0.0: {} + + crelt@1.0.7: {} + + css-tree@3.2.1: + dependencies: + mdn-data: 2.27.1 + source-map-js: 1.2.1 + + css.escape@1.5.1: {} + + cssstyle@5.3.7: + dependencies: + '@asamuzakjp/css-color': 4.1.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.7(css-tree@3.2.1) + css-tree: 3.2.1 + lru-cache: 11.5.2 + + csstype@3.2.3: {} + + d3-color@3.1.0: {} + + d3-dispatch@3.0.1: {} + + d3-drag@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-selection: 3.0.0 + + d3-ease@3.0.1: {} + + d3-interpolate@3.0.1: + dependencies: + d3-color: 3.1.0 + + d3-selection@3.0.0: {} + + d3-timer@3.0.1: {} + + d3-transition@3.0.1(d3-selection@3.0.0): + dependencies: + d3-color: 3.1.0 + d3-dispatch: 3.0.1 + d3-ease: 3.0.1 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-timer: 3.0.1 + + d3-zoom@3.0.0: + dependencies: + d3-dispatch: 3.0.1 + d3-drag: 3.0.0 + d3-interpolate: 3.0.1 + d3-selection: 3.0.0 + d3-transition: 3.0.1(d3-selection@3.0.0) + + data-urls@6.0.1: + dependencies: + whatwg-mimetype: 5.0.0 + whatwg-url: 15.1.0 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decimal.js@10.6.0: {} + + decode-named-character-reference@1.3.0: + dependencies: + character-entities: 2.0.2 + + deep-eql@5.0.2: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dom-accessibility-api@0.5.16: {} + + dom-accessibility-api@0.6.3: {} + + electron-to-chromium@1.5.399: {} + + enhanced-resolve@5.24.5: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + entities@8.0.0: {} + + es-module-lexer@1.7.0: {} + + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + + escalade@3.2.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.9 + + expect-type@1.4.0: {} + + extend@3.0.2: {} + + fdir@6.5.0(picomatch@4.0.5): + optionalDependencies: + picomatch: 4.0.5 + + fsevents@2.3.3: + optional: true + + gensync@1.0.0-beta.2: {} + + graceful-fs@4.2.11: {} + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.9 + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + html-encoding-sniffer@6.0.0: + dependencies: + '@exodus/bytes': 1.15.1 + transitivePeerDependencies: + - '@noble/hashes' + + html-url-attributes@3.0.1: {} + + http-proxy-agent@7.0.2: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + indent-string@4.0.0: {} + + inline-style-parser@0.2.7: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-hexadecimal@2.0.1: {} + + is-plain-obj@4.1.0: {} + + is-potential-custom-element-name@1.0.1: {} + + jiti@2.7.0: {} + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + jsdom@27.4.0: + dependencies: + '@acemir/cssom': 0.9.31 + '@asamuzakjp/dom-selector': 6.8.1 + '@exodus/bytes': 1.15.1 + cssstyle: 5.3.7 + data-urls: 6.0.1 + 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.1 + saxes: 6.0.0 + symbol-tree: 3.2.4 + tough-cookie: 6.0.2 + w3c-xmlserializer: 5.0.0 + webidl-conversions: 8.0.1 + whatwg-mimetype: 4.0.0 + whatwg-url: 15.1.0 + ws: 8.21.1 + xml-name-validator: 5.0.0 + transitivePeerDependencies: + - '@noble/hashes' + - bufferutil + - supports-color + - utf-8-validate + + jsesc@3.1.0: {} + + json5@2.2.3: {} + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + longest-streak@3.1.0: {} + + loupe@3.2.1: {} + + lru-cache@11.5.2: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@1.28.0(react@19.2.8): + dependencies: + react: 19.2.8 + + lz-string@1.5.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + mdast-util-from-markdown@2.0.3: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-decode-string: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + unist-util-stringify-position: 4.0.0 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-expression@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-mdx-jsx@3.2.0: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + parse-entities: 4.0.2 + stringify-entities: 4.0.4 + unist-util-stringify-position: 4.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + mdast-util-mdxjs-esm@2.0.1: + dependencies: + '@types/estree-jsx': 1.0.5 + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + devlop: 1.1.0 + mdast-util-from-markdown: 2.0.3 + mdast-util-to-markdown: 2.1.2 + transitivePeerDependencies: + - supports-color + + mdast-util-phrasing@4.1.0: + dependencies: + '@types/mdast': 4.0.4 + unist-util-is: 6.0.1 + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.3 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + mdast-util-to-markdown@2.1.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + longest-streak: 3.1.0 + mdast-util-phrasing: 4.1.0 + mdast-util-to-string: 4.0.0 + micromark-util-classify-character: 2.0.1 + micromark-util-decode-string: 2.0.1 + unist-util-visit: 5.1.0 + zwitch: 2.0.4 + + mdast-util-to-string@4.0.0: + dependencies: + '@types/mdast': 4.0.4 + + mdn-data@2.27.1: {} + + micromark-core-commonmark@2.0.3: + dependencies: + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-factory-destination: 2.0.1 + micromark-factory-label: 2.0.1 + micromark-factory-space: 2.0.1 + micromark-factory-title: 2.0.1 + micromark-factory-whitespace: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-classify-character: 2.0.1 + micromark-util-html-tag-name: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-destination@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-label@2.0.1: + dependencies: + devlop: 1.1.0 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-space@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-types: 2.0.2 + + micromark-factory-title@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-factory-whitespace@2.0.1: + dependencies: + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-chunked@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-classify-character@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-combine-extensions@2.0.1: + dependencies: + micromark-util-chunked: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-decode-numeric-character-reference@2.0.2: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-decode-string@2.0.1: + dependencies: + decode-named-character-reference: 1.3.0 + micromark-util-character: 2.1.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-symbol: 2.0.1 + + micromark-util-encode@2.0.1: {} + + micromark-util-html-tag-name@2.0.1: {} + + micromark-util-normalize-identifier@2.0.1: + dependencies: + micromark-util-symbol: 2.0.1 + + micromark-util-resolve-all@2.0.1: + dependencies: + micromark-util-types: 2.0.2 + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-subtokenize@2.1.0: + dependencies: + devlop: 1.1.0 + micromark-util-chunked: 2.0.1 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromark@4.0.2: + dependencies: + '@types/debug': 4.1.13 + debug: 4.4.3 + decode-named-character-reference: 1.3.0 + devlop: 1.1.0 + micromark-core-commonmark: 2.0.3 + micromark-factory-space: 2.0.1 + micromark-util-character: 2.1.1 + micromark-util-chunked: 2.0.1 + micromark-util-combine-extensions: 2.0.1 + micromark-util-decode-numeric-character-reference: 2.0.2 + micromark-util-encode: 2.0.1 + micromark-util-normalize-identifier: 2.0.1 + micromark-util-resolve-all: 2.0.1 + micromark-util-sanitize-uri: 2.0.1 + micromark-util-subtokenize: 2.1.0 + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + transitivePeerDependencies: + - supports-color + + min-indent@1.0.1: {} + + ms@2.1.3: {} + + nanoid@3.3.16: {} + + node-releases@2.0.51: {} + + parse-entities@4.0.2: + dependencies: + '@types/unist': 2.0.11 + character-entities-legacy: 3.0.0 + character-reference-invalid: 2.0.1 + decode-named-character-reference: 1.3.0 + is-alphanumerical: 2.0.1 + is-decimal: 2.0.1 + is-hexadecimal: 2.0.1 + + parse5@8.0.1: + dependencies: + entities: 8.0.0 + + pathe@2.0.3: {} + + pathval@2.0.1: {} + + picocolors@1.1.1: {} + + picomatch@4.0.5: {} + + postcss@8.5.25: + dependencies: + nanoid: 3.3.16 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + pretty-format@27.5.1: + dependencies: + ansi-regex: 5.0.1 + ansi-styles: 5.2.0 + react-is: 17.0.2 + + property-information@7.2.0: {} + + punycode@2.3.1: {} + + react-dom@19.2.8(react@19.2.8): + dependencies: + react: 19.2.8 + scheduler: 0.27.0 + + react-is@17.0.2: {} + + react-markdown@10.1.0(@types/react@19.2.18)(react@19.2.8): + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + '@types/react': 19.2.18 + devlop: 1.1.0 + hast-util-to-jsx-runtime: 2.3.6 + html-url-attributes: 3.0.1 + mdast-util-to-hast: 13.2.1 + react: 19.2.8 + remark-parse: 11.0.0 + remark-rehype: 11.1.2 + unified: 11.0.5 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + transitivePeerDependencies: + - supports-color + + react-refresh@0.18.0: {} + + react@19.2.8: {} + + redent@3.0.0: + dependencies: + indent-string: 4.0.0 + strip-indent: 3.0.0 + + remark-parse@11.0.0: + dependencies: + '@types/mdast': 4.0.4 + mdast-util-from-markdown: 2.0.3 + micromark-util-types: 2.0.2 + unified: 11.0.5 + transitivePeerDependencies: + - supports-color + + remark-rehype@11.1.2: + dependencies: + '@types/hast': 3.0.5 + '@types/mdast': 4.0.4 + mdast-util-to-hast: 13.2.1 + unified: 11.0.5 + vfile: 6.0.3 + + require-from-string@2.0.2: {} + + rollup@4.62.3: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.62.3 + '@rollup/rollup-android-arm64': 4.62.3 + '@rollup/rollup-darwin-arm64': 4.62.3 + '@rollup/rollup-darwin-x64': 4.62.3 + '@rollup/rollup-freebsd-arm64': 4.62.3 + '@rollup/rollup-freebsd-x64': 4.62.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.62.3 + '@rollup/rollup-linux-arm-musleabihf': 4.62.3 + '@rollup/rollup-linux-arm64-gnu': 4.62.3 + '@rollup/rollup-linux-arm64-musl': 4.62.3 + '@rollup/rollup-linux-loong64-gnu': 4.62.3 + '@rollup/rollup-linux-loong64-musl': 4.62.3 + '@rollup/rollup-linux-ppc64-gnu': 4.62.3 + '@rollup/rollup-linux-ppc64-musl': 4.62.3 + '@rollup/rollup-linux-riscv64-gnu': 4.62.3 + '@rollup/rollup-linux-riscv64-musl': 4.62.3 + '@rollup/rollup-linux-s390x-gnu': 4.62.3 + '@rollup/rollup-linux-x64-gnu': 4.62.3 + '@rollup/rollup-linux-x64-musl': 4.62.3 + '@rollup/rollup-openbsd-x64': 4.62.3 + '@rollup/rollup-openharmony-arm64': 4.62.3 + '@rollup/rollup-win32-arm64-msvc': 4.62.3 + '@rollup/rollup-win32-ia32-msvc': 4.62.3 + '@rollup/rollup-win32-x64-gnu': 4.62.3 + '@rollup/rollup-win32-x64-msvc': 4.62.3 + fsevents: 2.3.3 + + saxes@6.0.0: + dependencies: + xmlchars: 2.2.0 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + siginfo@2.0.0: {} + + source-map-js@1.2.1: {} + + space-separated-tokens@2.0.2: {} + + stackback@0.0.2: {} + + std-env@3.10.0: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-indent@3.0.0: + dependencies: + min-indent: 1.0.1 + + strip-literal@3.1.0: + dependencies: + js-tokens: 9.0.1 + + style-mod@4.1.3: {} + + style-to-js@1.1.21: + dependencies: + style-to-object: 1.0.14 + + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + + symbol-tree@3.2.4: {} + + tailwindcss@4.3.3: {} + + tapable@2.3.3: {} + + tinybench@2.9.0: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + + tinypool@1.1.1: {} + + tinyrainbow@2.0.0: {} + + tinyspy@4.0.4: {} + + tldts-core@7.4.10: {} + + tldts@7.4.10: + dependencies: + tldts-core: 7.4.10 + + tough-cookie@6.0.2: + dependencies: + tldts: 7.4.10 + + tr46@6.0.0: + dependencies: + punycode: 2.3.1 + + trim-lines@3.0.1: {} + + trough@2.2.0: {} + + typescript@3.9.10: {} + + typescript@5.4.5: {} + + typescript@5.9.3: {} + + unified@11.0.5: + dependencies: + '@types/unist': 3.0.3 + bail: 2.0.2 + devlop: 1.1.0 + extend: 3.0.2 + is-plain-obj: 4.1.0 + trough: 2.2.0 + vfile: 6.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + update-browserslist-db@1.2.3(browserslist@4.28.7): + dependencies: + browserslist: 4.28.7 + escalade: 3.2.0 + picocolors: 1.1.1 + + use-sync-external-store@1.6.0(react@19.2.8): + dependencies: + react: 19.2.8 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite-node@3.2.4(jiti@2.7.0)(lightningcss@1.32.0): + dependencies: + cac: 6.7.14 + debug: 4.4.3 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 7.3.6(jiti@2.7.0)(lightningcss@1.32.0) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0): + dependencies: + esbuild: 0.28.1 + fdir: 6.5.0(picomatch@4.0.5) + picomatch: 4.0.5 + postcss: 8.5.25 + rollup: 4.62.3 + tinyglobby: 0.2.17 + optionalDependencies: + fsevents: 2.3.3 + jiti: 2.7.0 + lightningcss: 1.32.0 + + vitest@3.2.7(@types/debug@4.1.13)(jiti@2.7.0)(jsdom@27.4.0)(lightningcss@1.32.0): + dependencies: + '@types/chai': 5.2.3 + '@vitest/expect': 3.2.7 + '@vitest/mocker': 3.2.7(vite@7.3.6(jiti@2.7.0)(lightningcss@1.32.0)) + '@vitest/pretty-format': 3.2.7 + '@vitest/runner': 3.2.7 + '@vitest/snapshot': 3.2.7 + '@vitest/spy': 3.2.7 + '@vitest/utils': 3.2.7 + chai: 5.3.3 + debug: 4.4.3 + expect-type: 1.4.0 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.5 + std-env: 3.10.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 7.3.6(jiti@2.7.0)(lightningcss@1.32.0) + vite-node: 3.2.4(jiti@2.7.0)(lightningcss@1.32.0) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.13 + jsdom: 27.4.0 + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + w3c-keyname@2.2.8: {} + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + webidl-conversions@8.0.1: {} + + whatwg-mimetype@4.0.0: {} + + whatwg-mimetype@5.0.0: {} + + whatwg-url@15.1.0: + dependencies: + tr46: 6.0.0 + webidl-conversions: 8.0.1 + + why-is-node-running@2.3.0: + dependencies: + siginfo: 2.0.0 + stackback: 0.0.2 + + ws@8.21.1: {} + + xml-name-validator@5.0.0: {} + + xmlchars@2.2.0: {} + + yallist@3.1.1: {} + + zustand@4.5.7(@types/react@19.2.18)(react@19.2.8): + dependencies: + use-sync-external-store: 1.6.0(react@19.2.8) + optionalDependencies: + '@types/react': 19.2.18 + react: 19.2.8 + + zwitch@2.0.4: {} diff --git a/web/operator/scripts/operator-large-run-browser-benchmark.mjs b/web/operator/scripts/operator-large-run-browser-benchmark.mjs new file mode 100644 index 0000000..cb4a4fc --- /dev/null +++ b/web/operator/scripts/operator-large-run-browser-benchmark.mjs @@ -0,0 +1,678 @@ +import { spawn } from "node:child_process"; +import { access, mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { basename, delimiter, dirname, join, resolve } from "node:path"; +import process from "node:process"; +import { fileURLToPath } from "node:url"; + +const RUN_COUNT = 10_000; +const DOM_ROW_LIMIT = 120; +const RUN_ROW_HEIGHT = 32; +const RENDER_BUDGET_MS = 3_000; +const INTERACTION_BUDGET_MS = 1_000; +const VITE_START_BUDGET_MS = 10_000; +const VITE_PROBE_BUDGET_MS = 500; +const CHROMIUM_PROCESS_BUDGET_MS = 15_000; + +const operatorRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); + +async function findChromiumExecutable() { + const pathDirectories = (process.env.PATH ?? "").split(delimiter).filter(Boolean); + const candidates = [ + process.env.OPERATOR_CHROMIUM, + process.env.CHROME_BIN, + "chromium", + "chromium-browser", + "google-chrome", + "google-chrome-stable", + "/opt/google/chrome/chrome", + ].filter(Boolean); + + for (const candidate of candidates) { + const paths = candidate.includes("/") + ? [resolve(candidate)] + : pathDirectories.map((directory) => join(directory, candidate)); + for (const executable of paths) { + try { + await access(executable); + return executable; + } catch { + // Try the next installed Chromium name. + } + } + } + throw new Error( + "Chromium is required for web-bench; install Chromium or set OPERATOR_CHROMIUM or CHROME_BIN", + ); +} + +async function waitForVite(url, server, stderr) { + const deadline = performance.now() + VITE_START_BUDGET_MS; + while (performance.now() < deadline) { + if (server.exitCode !== null) { + throw new Error(`Vite exited before serving the benchmark fixture: ${stderr()}`); + } + + const controller = new AbortController(); + const timeout = setTimeout( + () => controller.abort(), + Math.min(VITE_PROBE_BUDGET_MS, deadline - performance.now()), + ); + try { + const response = await fetch(url, { signal: controller.signal }); + if (response.ok) return; + } catch { + // The socket may not be listening yet, or the readiness probe may have timed out. + } finally { + clearTimeout(timeout); + } + + const remaining = deadline - performance.now(); + if (remaining > 0) { + await new Promise((resolvePromise) => setTimeout(resolvePromise, Math.min(50, remaining))); + } + } + + const output = stderr().trim(); + throw new Error( + `Vite did not start within ${VITE_START_BUDGET_MS}ms${output ? `:\n${output}` : ""}`, + ); +} + +function delay(milliseconds) { + return new Promise((resolvePromise) => setTimeout(resolvePromise, milliseconds)); +} + +function childHasClosed(child) { + return child.exitCode !== null || child.signalCode !== null; +} + +function signalProcessTree(child, signal) { + if (child.pid !== undefined && process.platform !== "win32") { + try { + process.kill(-child.pid, signal); + return; + } catch (error) { + if (error?.code !== "ESRCH") throw error; + } + } + if (!childHasClosed(child)) child.kill(signal); +} + +async function waitForClose(closed, milliseconds) { + return Promise.race([ + closed.then(() => true), + delay(milliseconds).then(() => false), + ]); +} + +async function terminateChromium(browser, closed, cdp) { + if (cdp && !childHasClosed(browser)) { + try { + await Promise.race([ + cdp.send("Browser.close", {}, performance.now() + 250).catch(() => {}), + delay(250), + ]); + } catch { + // Fall through to terminating the whole process group. + } + } + cdp?.close(); + + if (!(await waitForClose(closed, 250))) { + signalProcessTree(browser, "SIGTERM"); + if (!(await waitForClose(closed, 500))) { + signalProcessTree(browser, "SIGKILL"); + } + } + await closed; + + // Chrome can leave renderer descendants alive after its root exits. A detached + // process group lets the harness terminate those descendants before removing + // the profile they may still be using. + if (browser.pid !== undefined && process.platform !== "win32") { + try { + process.kill(-browser.pid, "SIGKILL"); + } catch (error) { + if (error?.code !== "ESRCH") throw error; + } + } +} + +async function fetchJsonBeforeDeadline(url, deadline) { + const remaining = deadline - performance.now(); + if (remaining <= 0) throw new Error("Chromium deadline expired"); + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), remaining); + try { + const response = await fetch(url, { signal: controller.signal }); + if (!response.ok) throw new Error(`DevTools endpoint returned ${response.status}`); + return await response.json(); + } finally { + clearTimeout(timeout); + } +} + +async function waitForDebuggerTarget(profilePath, browser, state, deadline) { + let debuggingPort; + let lastError; + while (performance.now() < deadline) { + if (state.launchError) throw state.launchError; + if (childHasClosed(browser)) { + throw new Error( + `Chromium exited before exposing DevTools (code ${browser.exitCode}, signal ${browser.signalCode})` + + (state.stderr ? `:\n${state.stderr}` : ""), + ); + } + + if (debuggingPort === undefined) { + try { + const contents = await readFile(join(profilePath, "DevToolsActivePort"), "utf8"); + const candidate = Number(contents.split(/\r?\n/, 1)[0]); + if (Number.isInteger(candidate) && candidate > 0) debuggingPort = candidate; + } catch (error) { + if (error?.code !== "ENOENT") lastError = error; + } + } + + if (debuggingPort !== undefined) { + try { + const targets = await fetchJsonBeforeDeadline( + `http://127.0.0.1:${debuggingPort}/json`, + deadline, + ); + const page = targets.find( + (target) => target.type === "page" && typeof target.webSocketDebuggerUrl === "string", + ); + if (page) return page.webSocketDebuggerUrl; + } catch (error) { + lastError = error; + } + } + await delay(Math.min(50, Math.max(0, deadline - performance.now()))); + } + throw new Error( + `Chromium did not expose a page DevTools target within ${CHROMIUM_PROCESS_BUDGET_MS}ms` + + (lastError ? `: ${lastError instanceof Error ? lastError.message : String(lastError)}` : "") + + (state.stderr ? `\n${state.stderr}` : ""), + ); +} + +async function connectCdp(webSocketUrl, deadline) { + if (typeof WebSocket !== "function") { + throw new Error("This benchmark requires a Node.js runtime with global WebSocket support"); + } + + const socket = new WebSocket(webSocketUrl); + const pending = new Map(); + const pageErrors = []; + let nextId = 1; + let closed = false; + + function rejectPending(error) { + for (const request of pending.values()) { + clearTimeout(request.timeout); + request.reject(error); + } + pending.clear(); + } + + socket.addEventListener("message", (event) => { + let message; + try { + message = JSON.parse(String(event.data)); + } catch { + return; + } + if (message.method === "Runtime.exceptionThrown") { + const details = message.params?.exceptionDetails; + pageErrors.push( + details?.exception?.description ?? details?.text ?? "Unknown page exception", + ); + return; + } + if (message.id === undefined) return; + const request = pending.get(message.id); + if (!request) return; + pending.delete(message.id); + clearTimeout(request.timeout); + if (message.error) { + request.reject( + new Error( + `CDP ${request.method} failed (${message.error.code}): ${message.error.message}`, + ), + ); + } else { + request.resolve(message.result); + } + }); + socket.addEventListener("close", () => { + closed = true; + rejectPending(new Error("Chromium DevTools connection closed")); + }); + socket.addEventListener("error", () => { + rejectPending(new Error("Chromium DevTools WebSocket failed")); + }); + + const remaining = deadline - performance.now(); + if (remaining <= 0) throw new Error("Chromium deadline expired before DevTools connected"); + await new Promise((resolvePromise, rejectPromise) => { + const timeout = setTimeout( + () => rejectPromise(new Error("Timed out connecting to Chromium DevTools")), + remaining, + ); + socket.addEventListener( + "open", + () => { + clearTimeout(timeout); + resolvePromise(); + }, + { once: true }, + ); + socket.addEventListener( + "close", + () => { + clearTimeout(timeout); + rejectPromise(new Error("Chromium DevTools connection closed before opening")); + }, + { once: true }, + ); + }); + + return { + pageErrors, + send(method, params = {}, commandDeadline = deadline) { + if (closed || socket.readyState !== WebSocket.OPEN) { + return Promise.reject(new Error(`Cannot send CDP ${method}: connection is closed`)); + } + const commandRemaining = commandDeadline - performance.now(); + if (commandRemaining <= 0) { + return Promise.reject(new Error(`Timed out before sending CDP ${method}`)); + } + const id = nextId++; + return new Promise((resolvePromise, rejectPromise) => { + const timeout = setTimeout(() => { + pending.delete(id); + rejectPromise(new Error(`Timed out waiting for CDP ${method}`)); + }, commandRemaining); + pending.set(id, { + method, + reject: rejectPromise, + resolve: resolvePromise, + timeout, + }); + try { + socket.send(JSON.stringify({ id, method, params })); + } catch (error) { + clearTimeout(timeout); + pending.delete(id); + rejectPromise(error); + } + }); + }, + close() { + if (!closed) socket.close(); + }, + }; +} + +async function readBenchmarkResult(cdp, browser, state, deadline) { + let latest = { bodyText: "", status: "" }; + while (performance.now() < deadline) { + if (state.launchError) throw state.launchError; + if (childHasClosed(browser)) { + throw new Error( + `Chromium exited during the benchmark (code ${browser.exitCode}, signal ${browser.signalCode})`, + ); + } + const evaluation = await cdp.send("Runtime.evaluate", { + expression: `(() => { + const body = document.body; + return { + status: body?.dataset.benchmarkStatus ?? "", + bodyText: body?.innerText ?? "", + domRows: body?.dataset.domRows ?? "", + interactionMs: body?.dataset.interactionMs ?? "", + renderMs: body?.dataset.renderMs ?? "", + runCount: body?.dataset.runCount ?? "", + }; + })()`, + returnByValue: true, + }); + if (evaluation.exceptionDetails) { + throw new Error( + evaluation.exceptionDetails.exception?.description ?? + evaluation.exceptionDetails.text ?? + "Benchmark result evaluation failed", + ); + } + latest = evaluation.result?.value ?? latest; + if (latest.status === "pass") { + if (cdp.pageErrors.length > 0) { + throw new Error(`Real-browser benchmark failed:\n${cdp.pageErrors.join("\n")}`); + } + return latest; + } + if (latest.status === "fail") { + throw new Error( + `Real-browser benchmark failed:\n${latest.bodyText || cdp.pageErrors.join("\n") || "Unknown page failure"}`, + ); + } + await delay(Math.min(25, Math.max(0, deadline - performance.now()))); + } + const details = [ + latest.bodyText, + ...cdp.pageErrors, + state.stderr && `Chromium stderr:\n${state.stderr}`, + ].filter(Boolean); + throw new Error( + `Chromium exceeded the ${CHROMIUM_PROCESS_BUDGET_MS}ms process budget` + + (details.length > 0 ? `\n${details.join("\n")}` : ""), + ); +} + +async function runChromiumBenchmark(executable, url, profilePath) { + const deadline = performance.now() + CHROMIUM_PROCESS_BUDGET_MS; + const browser = spawn( + executable, + [ + "--headless=new", + "--disable-dev-shm-usage", + "--disable-gpu", + "--no-sandbox", + "--no-first-run", + "--no-default-browser-check", + "--remote-allow-origins=*", + "--remote-debugging-port=0", + `--user-data-dir=${profilePath}`, + "--window-size=1280,900", + "about:blank", + ], + { + detached: process.platform !== "win32", + stdio: ["ignore", "ignore", "pipe"], + }, + ); + browser.stderr.setEncoding("utf8"); + const state = { launchError: undefined, stderr: "" }; + browser.stderr.on("data", (chunk) => { + state.stderr = (state.stderr + chunk).slice(-4_000); + }); + browser.once("error", (error) => { + state.launchError = error; + }); + const closed = new Promise((resolvePromise) => { + browser.once("close", (code, signal) => resolvePromise({ code, signal })); + }); + + let cdp; + let result; + let primaryError; + try { + const webSocketUrl = await waitForDebuggerTarget(profilePath, browser, state, deadline); + cdp = await connectCdp(webSocketUrl, deadline); + await cdp.send("Page.enable"); + await cdp.send("Runtime.enable"); + const navigation = await cdp.send("Page.navigate", { url }); + if (navigation.errorText) { + throw new Error( + `Chromium could not navigate to the benchmark fixture: ${navigation.errorText}`, + ); + } + result = await readBenchmarkResult(cdp, browser, state, deadline); + } catch (error) { + primaryError = error; + } finally { + try { + await terminateChromium(browser, closed, cdp); + } catch (error) { + if (primaryError) { + process.stderr.write( + `Chromium cleanup also failed: ${error instanceof Error ? error.message : String(error)}\n`, + ); + } else { + primaryError = error; + } + } + } + + if (primaryError) throw primaryError; + return result; +} + +function browserBenchmarkFixture() { + return ` +import React from "react"; +import { createRoot } from "react-dom/client"; +import { RunListPanel } from "/src/RunListPanel"; +import "/src/style.css"; + +const RUN_COUNT = ${RUN_COUNT}; +const DOM_ROW_LIMIT = ${DOM_ROW_LIMIT}; +const RUN_ROW_HEIGHT = ${RUN_ROW_HEIGHT}; +const RENDER_BUDGET_MS = ${RENDER_BUDGET_MS}; +const INTERACTION_BUDGET_MS = ${INTERACTION_BUDGET_MS}; +const workflowId = "benchmark.py::large_run"; +const summaries = Array.from({ length: RUN_COUNT }, (_, index) => { + const runId = "run-" + index.toString().padStart(5, "0"); + return { + runId, + workflowId, + workflowDisplayName: "Benchmark flow", + status: index % 7 === 0 ? "failed" : "success", + startedAt: index + 1, + endedAt: index + 2, + createdSequence: String(index + 1), + revision: String(index + 1), + }; +}); +const runs = Object.fromEntries(summaries.map((summary) => [summary.runId, summary])); + +async function until( + find: () => T | undefined, + budgetMs: number, + message: string, +) { + const startedAt = performance.now(); + while (performance.now() - startedAt <= budgetMs) { + const found = find(); + if (found) return found; + await new Promise((resolvePromise) => requestAnimationFrame(() => resolvePromise())); + } + throw new Error(message); +} +function rows() { + return Array.from(document.querySelectorAll(".run-list-row")); +} +function assertDomBound() { + if (rows().length === 0 || rows().length > DOM_ROW_LIMIT) { + throw new Error("virtualized run DOM exceeded " + DOM_ROW_LIMIT + ": " + rows().length); + } +} + +async function run() { + const rootElement = document.getElementById("root"); + if (!rootElement) throw new Error("benchmark root missing"); + let selectedRunId = ""; + const renderStartedAt = performance.now(); + createRoot(rootElement).render( +
+ { + selectedRunId = runId; + }} + /> +
, + ); + const panel = await until( + () => document.querySelector(".run-list-panel") ?? undefined, + RENDER_BUDGET_MS, + "Run list panel did not render", + ); + const virtualList = await until( + () => document.querySelector(".run-list-virtual") ?? undefined, + RENDER_BUDGET_MS, + "virtual run list did not render", + ); + await until( + () => Array.from(document.querySelectorAll(".run-list-row")) + .some((row) => row.textContent?.includes("run-09999")) ? virtualList : undefined, + RENDER_BUDGET_MS, + "production virtualizer did not emit the initial visible range", + ); + const renderMs = performance.now() - renderStartedAt; + if (renderMs > RENDER_BUDGET_MS) { + throw new Error("initial render exceeded " + RENDER_BUDGET_MS + "ms: " + renderMs); + } + if (virtualList.getBoundingClientRect().height < RUN_COUNT * RUN_ROW_HEIGHT) { + throw new Error("virtual list did not retain deterministic 10k-row geometry"); + } + assertDomBound(); + const scrollElement = panel.querySelector(".run-list-scroll"); + if (!scrollElement) throw new Error("run list scroll element missing"); + + const interactionStartedAt = performance.now(); + scrollElement.scrollTop = scrollElement.scrollHeight - scrollElement.clientHeight; + scrollElement.dispatchEvent(new Event("scroll")); + const oldestRun = await until( + () => Array.from(document.querySelectorAll(".run-list-row")) + .find((button) => button.textContent?.includes("run-00000")), + INTERACTION_BUDGET_MS, + "scroll did not render the oldest run", + ); + const interactionMs = performance.now() - interactionStartedAt; + if (interactionMs > INTERACTION_BUDGET_MS) { + throw new Error( + "scroll interaction exceeded " + INTERACTION_BUDGET_MS + "ms: " + interactionMs, + ); + } + assertDomBound(); + oldestRun.click(); + if (selectedRunId !== "run-00000") throw new Error("oldest run interaction failed"); + + document.body.dataset.benchmarkStatus = "pass"; + document.body.dataset.domRows = String(rows().length); + document.body.dataset.interactionMs = interactionMs.toFixed(2); + document.body.dataset.renderMs = renderMs.toFixed(2); + document.body.dataset.runCount = String(RUN_COUNT); +} + +run().catch((error) => { + document.body.dataset.benchmarkStatus = "fail"; + document.body.textContent = error instanceof Error ? error.stack ?? error.message : String(error); +}); +`; +} + +function assertBrowserResult(result) { + const domRows = Number(result.domRows); + const interactionMs = Number(result.interactionMs); + const renderMs = Number(result.renderMs); + if (result.runCount !== String(RUN_COUNT)) { + throw new Error(`Chromium result did not retain ${RUN_COUNT} Explorer runs`); + } + if (!(domRows > 0 && domRows <= DOM_ROW_LIMIT)) { + throw new Error(`Chromium retained ${domRows} run rows; expected 1..${DOM_ROW_LIMIT}`); + } + if (!(interactionMs <= INTERACTION_BUDGET_MS)) { + throw new Error( + `Chromium interaction took ${interactionMs}ms; budget is ${INTERACTION_BUDGET_MS}ms`, + ); + } + if (!(renderMs <= RENDER_BUDGET_MS)) { + throw new Error(`Chromium render took ${renderMs}ms; budget is ${RENDER_BUDGET_MS}ms`); + } + process.stdout.write( + `Operator Chromium benchmark passed: ${RUN_COUNT} runs, ${domRows} DOM rows, ` + + `${renderMs.toFixed(2)}ms render, ${interactionMs.toFixed(2)}ms interaction\n`, + ); +} + +async function main() { + const chromium = await findChromiumExecutable(); + const fixtureDirectory = await mkdtemp(join(operatorRoot, "operator-browser-benchmark-")); + const chromiumProfile = await mkdtemp(join(tmpdir(), "avalanche-operator-chromium-")); + let viteServer; + let viteOutput = ""; + let primaryError; + try { + await writeFile( + join(fixtureDirectory, "index.html"), + ` + + + + + Operator real virtualizer benchmark + + +
+ + + +`, + ); + await writeFile(join(fixtureDirectory, "fixture.tsx"), browserBenchmarkFixture()); + await writeFile( + join(fixtureDirectory, "vite.benchmark.config.mjs"), + `import tailwindcss from "@tailwindcss/vite"; +export default { plugins: [tailwindcss()], server: { hmr: false } };`, + ); + + const port = 41_000 + (process.pid % 1_000); + const fixtureUrl = `http://127.0.0.1:${port}/${basename(fixtureDirectory)}/index.html`; + viteServer = spawn( + process.execPath, + [ + join(operatorRoot, "node_modules/vite/bin/vite.js"), + "--host", + "127.0.0.1", + "--port", + String(port), + "--strictPort", + "--config", + join(fixtureDirectory, "vite.benchmark.config.mjs"), + ], + { cwd: operatorRoot, stdio: ["ignore", "pipe", "pipe"] }, + ); + viteServer.stdout.setEncoding("utf8"); + viteServer.stderr.setEncoding("utf8"); + viteServer.stdout.on("data", (chunk) => { + viteOutput += chunk; + }); + viteServer.stderr.on("data", (chunk) => { + viteOutput += chunk; + }); + await waitForVite(fixtureUrl, viteServer, () => viteOutput); + assertBrowserResult(await runChromiumBenchmark(chromium, fixtureUrl, chromiumProfile)); + } catch (error) { + primaryError = error; + } finally { + if (viteServer?.exitCode === null) viteServer.kill("SIGTERM"); + try { + await Promise.all([ + rm(fixtureDirectory, { force: true, maxRetries: 10, recursive: true, retryDelay: 100 }), + rm(chromiumProfile, { force: true, maxRetries: 10, recursive: true, retryDelay: 100 }), + ]); + } catch (error) { + if (primaryError) { + process.stderr.write( + `Benchmark cleanup also failed: ${error instanceof Error ? error.message : String(error)}\n`, + ); + } else { + primaryError = error; + } + } + } + if (primaryError) { + if (viteOutput) process.stderr.write(`Vite output:\n${viteOutput}\n`); + throw primaryError; + } +} + +main().catch((error) => { + process.stderr.write(`${error instanceof Error ? error.stack ?? error.message : String(error)}\n`); + process.exitCode = 1; +}); diff --git a/web/operator/src/AnsiText.test.tsx b/web/operator/src/AnsiText.test.tsx new file mode 100644 index 0000000..e0122d4 --- /dev/null +++ b/web/operator/src/AnsiText.test.tsx @@ -0,0 +1,28 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it } from "vitest"; + +import { AnsiText } from "./AnsiText"; + +describe("AnsiText", () => { + it("renders basic ANSI styles and resets them", () => { + render(
); + + expect(screen.getByText("success")).toHaveStyle({ + color: "rgb(22, 128, 93)", + fontWeight: "700", + }); + expect(screen.getByTestId("ansi-output").lastChild?.nodeType).toBe(Node.TEXT_NODE); + expect(document.body.textContent).not.toContain("\u001b["); + }); + + it("supports xterm and true-color foreground sequences", () => { + render( +
+        
+      
, + ); + + expect(screen.getByText("orange")).toHaveStyle({ color: "rgb(255, 135, 0)" }); + expect(screen.getByText("rgb")).toHaveStyle({ color: "rgb(1, 2, 3)" }); + }); +}); diff --git a/web/operator/src/AnsiText.tsx b/web/operator/src/AnsiText.tsx new file mode 100644 index 0000000..24ff628 --- /dev/null +++ b/web/operator/src/AnsiText.tsx @@ -0,0 +1,180 @@ +import { type CSSProperties, type ReactNode } from "react"; + +interface AnsiState { + foreground?: string; + background?: string; + bold: boolean; + dim: boolean; + italic: boolean; + underline: boolean; + inverse: boolean; + strikethrough: boolean; +} + +interface AnsiSegment { + text: string; + state: AnsiState; +} + +const SGR_SEQUENCE = /\u001B\[([0-9;]*)m/g; +const ANSI_COLORS = [ + "#1f2937", + "#c43d36", + "#16805d", + "#a15c00", + "#2563eb", + "#a855f7", + "#0f766e", + "#dfe4e1", + "#64748b", + "#ef4444", + "#22c55e", + "#f59e0b", + "#3b82f6", + "#c084fc", + "#14b8a6", + "#ffffff", +] as const; + +function initialState(): AnsiState { + return { + foreground: undefined, + background: undefined, + bold: false, + dim: false, + italic: false, + underline: false, + inverse: false, + strikethrough: false, + }; +} + +function isByte(value: number | undefined): value is number { + return value !== undefined && value >= 0 && value <= 255; +} + +function rgb(red: number, green: number, blue: number): string { + return `rgb(${red}, ${green}, ${blue})`; +} + +function xtermColor(value: number): string { + if (value < ANSI_COLORS.length) return ANSI_COLORS[value]; + if (value < 232) { + const index = value - 16; + const levels = [0, 95, 135, 175, 215, 255]; + return rgb( + levels[Math.floor(index / 36)], + levels[Math.floor((index % 36) / 6)], + levels[index % 6], + ); + } + const gray = 8 + (value - 232) * 10; + return rgb(gray, gray, gray); +} + +function parameters(raw: string): number[] { + if (!raw) return [0]; + return raw.split(";").flatMap((part) => { + const value = Number(part); + return Number.isInteger(value) && value >= 0 ? [value] : []; + }); +} + +function applySgr(state: AnsiState, values: number[]): AnsiState { + const next = { ...state }; + for (let index = 0; index < values.length; index += 1) { + const value = values[index]; + if (value === 0) { + Object.assign(next, initialState()); + } else if (value === 1) { + next.bold = true; + } else if (value === 2) { + next.dim = true; + } else if (value === 3) { + next.italic = true; + } else if (value === 4) { + next.underline = true; + } else if (value === 7) { + next.inverse = true; + } else if (value === 9) { + next.strikethrough = true; + } else if (value === 22) { + next.bold = false; + next.dim = false; + } else if (value === 23) { + next.italic = false; + } else if (value === 24) { + next.underline = false; + } else if (value === 27) { + next.inverse = false; + } else if (value === 29) { + next.strikethrough = false; + } else if (value === 39) { + next.foreground = undefined; + } else if (value === 49) { + next.background = undefined; + } else if (value >= 30 && value <= 37) { + next.foreground = ANSI_COLORS[value - 30]; + } else if (value >= 40 && value <= 47) { + next.background = ANSI_COLORS[value - 40]; + } else if (value >= 90 && value <= 97) { + next.foreground = ANSI_COLORS[value - 90 + 8]; + } else if (value >= 100 && value <= 107) { + next.background = ANSI_COLORS[value - 100 + 8]; + } else if (value === 38 || value === 48) { + const target = value === 38 ? "foreground" : "background"; + const mode = values[index + 1]; + if (mode === 5 && isByte(values[index + 2])) { + next[target] = xtermColor(values[index + 2]); + index += 2; + } else if ( + mode === 2 && + isByte(values[index + 2]) && + isByte(values[index + 3]) && + isByte(values[index + 4]) + ) { + next[target] = rgb(values[index + 2], values[index + 3], values[index + 4]); + index += 4; + } + } + } + return next; +} + +function segments(text: string): AnsiSegment[] { + const result: AnsiSegment[] = []; + let state = initialState(); + let start = 0; + for (const match of text.matchAll(SGR_SEQUENCE)) { + if (match.index > start) result.push({ text: text.slice(start, match.index), state }); + state = applySgr(state, parameters(match[1])); + start = match.index + match[0].length; + } + if (start < text.length) result.push({ text: text.slice(start), state }); + return result; +} + +function styleFor(state: AnsiState): CSSProperties | undefined { + const foreground = state.inverse ? state.background ?? "#ffffff" : state.foreground; + const background = state.inverse ? state.foreground ?? "#17211c" : state.background; + if (!foreground && !background && !state.bold && !state.dim && !state.italic && !state.underline && !state.strikethrough) { + return undefined; + } + return { + color: foreground, + backgroundColor: background, + fontWeight: state.bold ? 700 : undefined, + opacity: state.dim ? 0.7 : undefined, + fontStyle: state.italic ? "italic" : undefined, + textDecoration: [state.underline ? "underline" : "", state.strikethrough ? "line-through" : ""] + .filter(Boolean) + .join(" ") || undefined, + }; +} + +export function AnsiText({ text }: { text: string }): ReactNode { + return segments(text).map((segment, index) => { + const style = styleFor(segment.state); + return style ? {segment.text} : segment.text; + }); +} diff --git a/web/operator/src/App.test.tsx b/web/operator/src/App.test.tsx new file mode 100644 index 0000000..d4987f1 --- /dev/null +++ b/web/operator/src/App.test.tsx @@ -0,0 +1,541 @@ +import type { ReactNode } from "react"; +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +vi.mock("@tanstack/react-virtual", () => ({ + useVirtualizer: ({ count }: { count: number }) => ({ + getTotalSize: () => count * 32, + getVirtualItems: () => + Array.from({ length: Math.min(count, 120) }, (_, index) => ({ + index, + size: 32, + start: index * 32, + })), + }), +})); + +const projectionHarness = vi.hoisted(() => ({ + state: { + catalog: { + operatorInstanceId: "operator-1", + asOfSequence: "1", + revision: "1", + workflows: [ + { + workflowId: "flow.py::demo", + displayName: "demo", + rootAlias: "examples", + relativeFile: "flow.py", + nodeIds: ["node-1"], + graph: { "node-1": { children: [] } }, + nodeTypes: { "node-1": "task" }, + displayNames: { "node-1": "Current node" }, + agentNodeIds: [], + agentMetadataJson: {}, + }, + ], + scanTargets: [ + { + alias: "examples", + targetPath: "/workspace/examples", + kind: "directory", + }, + ], + diagnostics: [], + }, + runs: {} as Record, + selectedRun: undefined as unknown, + selectedRunId: undefined as string | undefined, + selectedRunStatus: "idle", + selectedRunError: undefined as string | undefined, + liveEvents: {}, + liveLogs: {}, + liveEventRepairWatermarks: {}, + liveLogRepairWatermarks: {}, + operatorInstanceId: "operator-1", + sequence: "1", + connection: "live", + }, + selectRun: vi.fn(async (_runId?: string) => undefined), + startRun: vi.fn(async () => "run-1"), + cancelRun: vi.fn(async () => undefined), +})); + +vi.mock("./GraphCanvas", () => ({ + GraphCanvas: ({ + runTopology, + topLeftPanel, + bottomRightPanel, + onOpenNode, + }: { + runTopology?: { displayNames: Record }; + topLeftPanel?: ReactNode; + bottomRightPanel?: ReactNode; + onOpenNode: (nodeId: string) => void; + }) => ( +
+
{topLeftPanel}
+ +
{bottomRightPanel}
+
+ ), +})); +vi.mock("./Inspector", () => ({ + Inspector: ({ + run, + onClose, + }: { + run?: { summary?: { runId: string } }; + onClose: () => void; + }) => ( +
+ {`Inspector ${run?.summary?.runId ?? "workflow"}`} + +
+ ), +})); +vi.mock("./RunLogPane", () => ({ + RunLogPane: ({ + nodeId, + liveLogs, + onSelectNode, + }: { + nodeId?: string; + liveLogs?: { sequence: string }[]; + onSelectNode: (nodeId: string) => void; + }) => ( +
+ {`Log scope ${nodeId ?? "all"}`} + {`Live logs ${liveLogs?.map((log) => log.sequence).join(",") ?? "none"}`} + +
+ ), +})); +vi.mock("./state", () => ({ + useOperatorProjection: () => projectionHarness, +})); + +import { App } from "./App"; +import { GrpcWebOperatorApi } from "./api"; +import { RunSnapshotMsg, RunSummaryMsg, WorkflowTopologyMsg } from "./generated/operator"; + +const summary = RunSummaryMsg.create({ + runId: "run-1", + workflowId: "flow.py::demo", + workflowDisplayName: "demo", + status: "running", + startedAt: 1, + createdSequence: "2", +}); + +function selectedSnapshot(runId: string, nodeName: string) { + return RunSnapshotMsg.create({ + operatorInstanceId: "operator-1", + asOfSequence: "2", + summary: RunSummaryMsg.create({ ...summary, runId }), + topology: WorkflowTopologyMsg.create({ + nodeIds: ["node-1"], + graph: { "node-1": { children: [] } }, + nodeTypes: { "node-1": "task" }, + displayNames: { "node-1": nodeName }, + }), + }); +} + +describe("App", () => { + beforeEach(() => { + projectionHarness.state.runs = {}; + projectionHarness.state.selectedRun = undefined; + projectionHarness.state.selectedRunId = undefined; + projectionHarness.state.selectedRunStatus = "idle"; + projectionHarness.state.selectedRunError = undefined; + projectionHarness.state.liveEvents = {}; + projectionHarness.state.liveLogs = {}; + projectionHarness.state.catalog.revision = "1"; + projectionHarness.state.sequence = "1"; + Object.defineProperty(window, "innerWidth", { + configurable: true, + writable: true, + value: 1024, + }); + projectionHarness.state.liveEventRepairWatermarks = {}; + projectionHarness.state.liveLogRepairWatermarks = {}; + projectionHarness.selectRun.mockClear(); + projectionHarness.startRun.mockClear(); + projectionHarness.cancelRun.mockClear(); + }); + + it("keeps Explorer accessible through the narrow navigation toggle", () => { + window.innerWidth = 375; + const { container } = render( + , + ); + const toggle = screen.getByRole("button", { name: "Explorer" }); + + expect(toggle).toHaveAttribute("aria-controls", "operator-explorer"); + expect(toggle).toHaveAttribute("aria-expanded", "false"); + expect(screen.getByRole("complementary", { name: "Explorer" })).toHaveAttribute( + "id", + "operator-explorer", + ); + + fireEvent.click(toggle); + + expect(toggle).toHaveAttribute("aria-expanded", "true"); + expect(container.querySelector(".app-shell")).toHaveClass("explorer-open"); + + fireEvent.click(screen.getByRole("button", { name: "Run" })); + expect(projectionHarness.startRun).toHaveBeenCalledWith("flow.py::demo", undefined); + }); + + it("starts a run without selecting it before preparation completes", async () => { + render(); + + fireEvent.click(screen.getByRole("button", { name: "Run" })); + + await waitFor(() => + expect(projectionHarness.startRun).toHaveBeenCalledWith("flow.py::demo", undefined), + ); + expect(projectionHarness.selectRun).not.toHaveBeenCalled(); + }); + + it("collapses and restores the desktop Explorer independently of the narrow toggle", () => { + const { container } = render( + , + ); + const toggle = screen.getByRole("button", { name: "Collapse Explorer" }); + const explorer = screen.getByRole("complementary", { name: "Explorer" }); + const narrowToggle = screen.getByRole("button", { name: "Explorer" }); + + expect(toggle).toHaveAttribute("aria-controls", "operator-explorer"); + expect(toggle).toHaveAttribute("aria-expanded", "true"); + expect(explorer).toContainElement(toggle); + expect(screen.getByRole("separator", { name: "Resize Explorer" })).toBeInTheDocument(); + + fireEvent.click(toggle); + + expect(container.querySelector(".app-shell")).toHaveClass("explorer-collapsed"); + const restore = screen.getByRole("button", { name: "Restore Explorer" }); + expect(restore).toHaveAttribute("aria-expanded", "false"); + expect(restore.closest(".dag-runs-panel")).not.toBeNull(); + expect(narrowToggle).toHaveAttribute("aria-expanded", "false"); + expect( + screen.queryByRole("separator", { name: "Resize Explorer" }), + ).not.toBeInTheDocument(); + expect(screen.getByRole("complementary", { name: "Explorer" })).toBe(explorer); + + fireEvent.click(restore); + + expect(container.querySelector(".app-shell")).not.toHaveClass("explorer-collapsed"); + expect(screen.getByRole("button", { name: "Collapse Explorer" })).toHaveAttribute( + "aria-expanded", + "true", + ); + expect(explorer).toContainElement( + screen.getByRole("button", { name: "Collapse Explorer" }), + ); + expect(screen.getByRole("separator", { name: "Resize Explorer" })).toBeInTheDocument(); + expect(screen.getByRole("complementary", { name: "Explorer" })).toBe(explorer); + }); + + it("maps divider arrow keys to physical movement and intended pane widths", () => { + const { container } = render( + , + ); + const workspace = container.querySelector(".workspace")!; + const explorerDivider = screen.getByRole("separator", { + name: "Resize Explorer", + }); + + expect(explorerDivider).toHaveAttribute("aria-valuenow", "280"); + expect(explorerDivider).toHaveAttribute("aria-valuetext", "280 pixels"); + + fireEvent.keyDown(explorerDivider, { key: "ArrowLeft" }); + expect(explorerDivider).toHaveAttribute("aria-valuenow", "264"); + expect(workspace.style.getPropertyValue("--workspace-explorer-width")).toBe( + "264px", + ); + + fireEvent.keyDown(explorerDivider, { key: "ArrowRight" }); + expect(explorerDivider).toHaveAttribute("aria-valuenow", "280"); + expect(workspace.style.getPropertyValue("--workspace-explorer-width")).toBe( + "280px", + ); + + fireEvent.click(screen.getByRole("button", { name: "Workflow graph" })); + const inspectorDivider = screen.getByRole("separator", { + name: "Resize Inspector", + }); + + expect(inspectorDivider).toHaveAttribute("aria-valuenow", "410"); + expect(inspectorDivider).toHaveAttribute("aria-valuetext", "410 pixels"); + + fireEvent.keyDown(inspectorDivider, { key: "ArrowLeft" }); + expect(inspectorDivider).toHaveAttribute("aria-valuenow", "426"); + expect(workspace.style.getPropertyValue("--workspace-inspector-width")).toBe( + "426px", + ); + + fireEvent.keyDown(inspectorDivider, { key: "ArrowRight" }); + expect(inspectorDivider).toHaveAttribute("aria-valuenow", "410"); + expect(workspace.style.getPropertyValue("--workspace-inspector-width")).toBe( + "410px", + ); + }); + + it("clamps direction-aware divider keyboard resizing without changing Home or End", () => { + const { container } = render( + , + ); + const workspace = container.querySelector(".workspace")!; + const explorerDivider = screen.getByRole("separator", { + name: "Resize Explorer", + }); + + expect(explorerDivider).toHaveAttribute("aria-orientation", "vertical"); + expect(explorerDivider).toHaveAttribute("aria-controls", "operator-explorer"); + expect(explorerDivider).toHaveAttribute("aria-valuemin", "220"); + expect(explorerDivider).toHaveAttribute("aria-valuemax", "420"); + fireEvent.keyDown(explorerDivider, { key: "Home" }); + fireEvent.keyDown(explorerDivider, { key: "ArrowLeft" }); + expect(explorerDivider).toHaveAttribute("aria-valuenow", "220"); + expect(workspace.style.getPropertyValue("--workspace-explorer-width")).toBe( + "220px", + ); + fireEvent.keyDown(explorerDivider, { key: "End" }); + fireEvent.keyDown(explorerDivider, { key: "ArrowRight" }); + expect(explorerDivider).toHaveAttribute("aria-valuenow", "420"); + expect(workspace.style.getPropertyValue("--workspace-explorer-width")).toBe( + "420px", + ); + + fireEvent.click(screen.getByRole("button", { name: "Workflow graph" })); + const inspectorDivider = screen.getByRole("separator", { + name: "Resize Inspector", + }); + + expect(inspectorDivider).toHaveAttribute("aria-orientation", "vertical"); + expect(inspectorDivider).toHaveAttribute("aria-controls", "operator-inspector"); + expect(inspectorDivider).toHaveAttribute("aria-valuemin", "320"); + expect(inspectorDivider).toHaveAttribute("aria-valuemax", "640"); + fireEvent.keyDown(inspectorDivider, { key: "Home" }); + fireEvent.keyDown(inspectorDivider, { key: "ArrowRight" }); + expect(inspectorDivider).toHaveAttribute("aria-valuenow", "320"); + expect(workspace.style.getPropertyValue("--workspace-inspector-width")).toBe( + "320px", + ); + fireEvent.keyDown(inspectorDivider, { key: "End" }); + fireEvent.keyDown(inspectorDivider, { key: "ArrowLeft" }); + expect(inspectorDivider).toHaveAttribute("aria-valuenow", "640"); + expect(workspace.style.getPropertyValue("--workspace-inspector-width")).toBe( + "640px", + ); + }); + + it("keeps pointer resizing aligned with each divider direction", () => { + const { container } = render( + , + ); + const workspace = container.querySelector(".workspace")!; + const explorerDivider = screen.getByRole("separator", { + name: "Resize Explorer", + }); + + fireEvent.pointerDown(explorerDivider, { pointerId: 1, clientX: 280 }); + fireEvent.pointerMove(explorerDivider, { pointerId: 1, clientX: 344 }); + fireEvent.pointerUp(explorerDivider, { pointerId: 1 }); + expect(explorerDivider).toHaveAttribute("aria-valuenow", "344"); + expect(workspace.style.getPropertyValue("--workspace-explorer-width")).toBe( + "344px", + ); + + fireEvent.click(screen.getByRole("button", { name: "Workflow graph" })); + const inspectorDivider = screen.getByRole("separator", { + name: "Resize Inspector", + }); + + fireEvent.pointerDown(inspectorDivider, { pointerId: 2, clientX: 700 }); + fireEvent.pointerMove(inspectorDivider, { pointerId: 2, clientX: 636 }); + fireEvent.pointerUp(inspectorDivider, { pointerId: 2 }); + expect(inspectorDivider).toHaveAttribute("aria-valuenow", "474"); + expect(workspace.style.getPropertyValue("--workspace-inspector-width")).toBe( + "474px", + ); + }); + + it("keeps transport sequence internal while log and trace updates retain catalog revision", () => { + const view = render(); + const catalogRevision = screen.getByText("catalog r1"); + + expect(view.container).not.toHaveTextContent(/seq 1/i); + expect(view.container).not.toHaveTextContent(/sequence 1/i); + + projectionHarness.state.sequence = "93"; + projectionHarness.state.liveLogs = { + "run-1": [{ sequence: "92" }], + }; + projectionHarness.state.liveEvents = { + "run-1:node-1": [{ eventSequence: "93" }], + }; + view.rerender(); + + expect(screen.getByText("catalog r1")).toBe(catalogRevision); + expect(view.container).not.toHaveTextContent(/seq 93/i); + expect(view.container).not.toHaveTextContent(/sequence 93/i); + }); + + it("removes the canvas header while preserving the retained snapshot explanation", async () => { + projectionHarness.state.runs = { "run-1": summary }; + const view = render(); + + fireEvent.click(await screen.findByRole("button", { name: /run-1/ })); + + expect(view.container.querySelector(".view-header")).not.toBeInTheDocument(); + expect(view.container).not.toHaveTextContent(/Historical run/i); + + projectionHarness.state.selectedRunId = "run-1"; + projectionHarness.state.selectedRunStatus = "ready"; + projectionHarness.state.selectedRun = selectedSnapshot("run-1", "Recorded node"); + view.rerender(); + + expect(screen.getByText("Immutable run snapshot")).toBeInTheDocument(); + expect( + screen.getByText("Current workflow changes do not alter this canvas"), + ).toBeInTheDocument(); + expect(view.container).not.toHaveTextContent(/Historical run/i); + projectionHarness.selectRun.mockClear(); + fireEvent.click(screen.getByRole("button", { name: "Current workflow" })); + expect(projectionHarness.selectRun).toHaveBeenCalledWith(undefined); + expect(screen.getByRole("button", { name: "Workflow graph" })).toBeInTheDocument(); + expect(screen.queryByText("Immutable run snapshot")).not.toBeInTheDocument(); + }); + + it("navigates summary-only runs with one demand-load selection and clears it", async () => { + projectionHarness.state.runs = { "run-1": summary }; + const view = render(); + + fireEvent.click(await screen.findByRole("button", { name: /run-1/ })); + + expect(projectionHarness.selectRun).toHaveBeenCalledTimes(1); + expect(projectionHarness.selectRun).toHaveBeenCalledWith("run-1"); + expect(screen.getByRole("heading", { name: "No run snapshot" })).toBeInTheDocument(); + + fireEvent.click(screen.getByRole("button", { name: /demoflow.py/ })); + expect(projectionHarness.selectRun).toHaveBeenLastCalledWith(undefined); + + fireEvent.click(screen.getByRole("button", { name: /run-1/ })); + view.unmount(); + expect(projectionHarness.selectRun).toHaveBeenLastCalledWith(undefined); + }); + + it("shows selected-run loading and error states without rendering stale snapshots", async () => { + projectionHarness.state.runs = { "run-1": summary }; + const view = render(); + fireEvent.click(await screen.findByRole("button", { name: /run-1/ })); + + projectionHarness.state.selectedRunId = "run-1"; + projectionHarness.state.selectedRunStatus = "loading"; + view.rerender(); + expect(screen.getByRole("heading", { name: "Loading run snapshot" })).toBeInTheDocument(); + + projectionHarness.state.selectedRunStatus = "error"; + projectionHarness.state.selectedRunError = "snapshot was evicted"; + view.rerender(); + expect(screen.getByRole("alert")).toHaveTextContent("snapshot was evicted"); + + projectionHarness.state.selectedRunStatus = "ready"; + projectionHarness.state.selectedRun = selectedSnapshot("run-2", "Stale node"); + view.rerender(); + expect(screen.queryByText(/Run graph/)).not.toBeInTheDocument(); + + projectionHarness.state.selectedRun = selectedSnapshot("run-1", "Recorded node"); + view.rerender(); + fireEvent.click(screen.getByRole("button", { name: "Run graph Recorded node" })); + expect(screen.getByText("Inspector run-1")).toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Cancel run" })); + expect(projectionHarness.cancelRun).toHaveBeenCalledWith("run-1"); + + projectionHarness.state.selectedRunId = "run-2"; + projectionHarness.state.selectedRun = selectedSnapshot("run-2", "New stale node"); + view.rerender(); + expect(screen.queryByText(/Run graph/)).not.toBeInTheDocument(); + expect(screen.queryByText(/Inspector/)).not.toBeInTheDocument(); + }); + it("reloads a surviving selected run once after baseline replacement", async () => { + projectionHarness.state.runs = { "run-1": summary }; + const view = render(); + fireEvent.click(await screen.findByRole("button", { name: /run-1/ })); + + projectionHarness.state.selectedRunId = "run-1"; + projectionHarness.state.selectedRunStatus = "ready"; + projectionHarness.state.selectedRun = selectedSnapshot("run-1", "Recorded node"); + view.rerender(); + projectionHarness.selectRun.mockClear(); + + projectionHarness.state.runs = { "run-1": summary }; + projectionHarness.state.selectedRunId = undefined; + projectionHarness.state.selectedRunStatus = "idle"; + projectionHarness.state.selectedRun = undefined; + view.rerender(); + + expect(projectionHarness.selectRun).toHaveBeenCalledTimes(1); + expect(projectionHarness.selectRun).toHaveBeenCalledWith("run-1"); + + view.rerender(); + expect(projectionHarness.selectRun).toHaveBeenCalledTimes(1); + }); + + it("falls back to the selected run's workflow when replacement omits its summary", async () => { + projectionHarness.state.runs = { "run-1": summary }; + const view = render(); + fireEvent.click(await screen.findByRole("button", { name: /run-1/ })); + + projectionHarness.state.selectedRunId = "run-1"; + projectionHarness.state.selectedRunStatus = "ready"; + projectionHarness.state.selectedRun = selectedSnapshot("run-1", "Recorded node"); + view.rerender(); + fireEvent.click(screen.getByRole("button", { name: "Run graph Recorded node" })); + expect(screen.getByText("Inspector run-1")).toBeInTheDocument(); + projectionHarness.selectRun.mockClear(); + + projectionHarness.state.runs = {}; + projectionHarness.state.selectedRunId = undefined; + projectionHarness.state.selectedRunStatus = "idle"; + projectionHarness.state.selectedRun = undefined; + view.rerender(); + + expect(projectionHarness.selectRun).toHaveBeenCalledTimes(1); + expect(projectionHarness.selectRun).toHaveBeenCalledWith(undefined); + expect(view.container.querySelector(".view-header")).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Workflow graph" })).toBeInTheDocument(); + expect(screen.queryByText(/Inspector/)).not.toBeInTheDocument(); + expect(view.container.querySelector(".breadcrumb")).not.toHaveTextContent("run-1"); + }); + + it("passes one run-wide live tail to the log pane and restores all-step scope", async () => { + projectionHarness.state.runs = { "run-1": summary }; + projectionHarness.state.liveLogs = { + "run-1": [{ sequence: "17" }, { sequence: "18" }], + }; + const view = render(); + fireEvent.click(await screen.findByRole("button", { name: /run-1/ })); + + projectionHarness.state.selectedRunId = "run-1"; + projectionHarness.state.selectedRunStatus = "ready"; + projectionHarness.state.selectedRun = selectedSnapshot("run-1", "Recorded node"); + view.rerender(); + + expect(screen.getByText("Live logs 17,18")).toBeInTheDocument(); + expect(screen.getByText("Log scope all")).toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Run graph Recorded node" })); + expect(screen.getByText("Log scope node-1")).toBeInTheDocument(); + expect(screen.getByText("Inspector run-1")).toBeInTheDocument(); + + fireEvent.click(screen.getByRole("button", { name: "Close inspector" })); + expect(screen.getByText("Log scope all")).toBeInTheDocument(); + expect(screen.queryByText("Inspector run-1")).not.toBeInTheDocument(); + }); + +}); diff --git a/web/operator/src/App.tsx b/web/operator/src/App.tsx new file mode 100644 index 0000000..bc0c7af --- /dev/null +++ b/web/operator/src/App.tsx @@ -0,0 +1,434 @@ +import { + type CSSProperties, + type KeyboardEvent, + type PointerEvent, + useCallback, + useEffect, + useRef, + useState, +} from "react"; +import { PanelLeftOpen } from "lucide-react"; + +import type { OperatorApi } from "./api"; +import { Explorer, type Selection } from "./Explorer"; +import { GraphCanvas } from "./GraphCanvas"; +import { Inspector } from "./Inspector"; +import { RunLogPane } from "./RunLogPane"; +import { RunControls } from "./RunControls"; +import { RunListPanel } from "./RunListPanel"; +import { useOperatorProjection } from "./state"; + +const avalancheDiamond = new URL( + "../../../docs/assets/brand/avalanche-diamond-3d-1024.png", + import.meta.url, +).href; + +const EXPLORER_MIN_WIDTH = 220; +const EXPLORER_MAX_WIDTH = 420; +const EXPLORER_DEFAULT_WIDTH = 280; +const INSPECTOR_MIN_WIDTH = 320; +const INSPECTOR_MAX_WIDTH = 640; +const INSPECTOR_DEFAULT_WIDTH = 410; +const PANEL_KEYBOARD_STEP = 16; + +interface WorkspaceDividerProps { + className: string; + label: string; + controls: string; + value: number; + min: number; + max: number; + pointerDirection: 1 | -1; + onChange: (value: number) => void; +} + + +function WorkspaceDivider({ + className, + label, + controls, + value, + min, + max, + pointerDirection, + onChange, +}: WorkspaceDividerProps) { + const dragStart = useRef<{ clientX: number; value: number } | undefined>(undefined); + + const endDrag = (event: PointerEvent) => { + if (!dragStart.current) return; + if (event.currentTarget.hasPointerCapture?.(event.pointerId)) { + event.currentTarget.releasePointerCapture(event.pointerId); + } + dragStart.current = undefined; + }; + + const resizeWithKeyboard = (event: KeyboardEvent) => { + let next: number | undefined; + if (event.key === "ArrowLeft") { + next = value - PANEL_KEYBOARD_STEP * pointerDirection; + } + if (event.key === "ArrowRight") { + next = value + PANEL_KEYBOARD_STEP * pointerDirection; + } + if (event.key === "Home") next = min; + if (event.key === "End") next = max; + if (next === undefined) return; + event.preventDefault(); + onChange(Math.min(max, Math.max(min, next))); + }; + + return ( +
{ + event.preventDefault(); + dragStart.current = { clientX: event.clientX, value }; + event.currentTarget.setPointerCapture?.(event.pointerId); + }} + onPointerMove={(event) => { + const start = dragStart.current; + if (!start) return; + const next = + start.value + (event.clientX - start.clientX) * pointerDirection; + onChange(Math.min(max, Math.max(min, next))); + }} + onPointerUp={endDrag} + onPointerCancel={endDrag} + /> + ); +} + +export function App({ api }: { api: OperatorApi }) { + const { state, startRun, cancelRun, selectRun } = useOperatorProjection(api); + const [selection, setSelection] = useState(); + const [inspectedNode, setInspectedNode] = useState(); + const [explorerOpen, setExplorerOpen] = useState(false); + const [explorerCollapsed, setExplorerCollapsed] = useState(false); + const [explorerWidth, setExplorerWidth] = useState(EXPLORER_DEFAULT_WIDTH); + const [inspectorWidth, setInspectorWidth] = useState(INSPECTOR_DEFAULT_WIDTH); + const previousSelectedRunId = useRef(state.selectedRunId); + + useEffect(() => { + const workflows = state.catalog?.workflows ?? []; + if (!workflows.length) { + if (selection) { + setSelection(undefined); + setInspectedNode(undefined); + void selectRun(undefined); + } + return; + } + if (!selection) { + setSelection({ kind: "workflow", workflowId: workflows[0].workflowId }); + return; + } + if (!workflows.some((workflow) => workflow.workflowId === selection.workflowId)) { + setSelection({ kind: "workflow", workflowId: workflows[0].workflowId }); + setInspectedNode(undefined); + void selectRun(undefined); + } + }, [selectRun, selection, state.catalog]); + + useEffect(() => { + const priorSelectedRunId = previousSelectedRunId.current; + previousSelectedRunId.current = state.selectedRunId; + if ( + selection?.kind !== "run" || + state.selectedRunId !== undefined || + state.selectedRunStatus !== "idle" || + priorSelectedRunId !== selection.runId + ) { + return; + } + + if (state.runs[selection.runId]) { + void selectRun(selection.runId); + return; + } + + const workflows = state.catalog?.workflows ?? []; + const workflow = + workflows.find((item) => item.workflowId === selection.workflowId) ?? workflows[0]; + setSelection( + workflow ? { kind: "workflow", workflowId: workflow.workflowId } : undefined, + ); + setInspectedNode(undefined); + void selectRun(undefined); + }, [ + selectRun, + selection, + state.catalog, + state.runs, + state.selectedRunId, + state.selectedRunStatus, + ]); + + useEffect( + () => () => { + void selectRun(undefined); + }, + [selectRun], + ); + + const workflow = state.catalog?.workflows.find( + (item) => item.workflowId === selection?.workflowId, + ); + const historical = selection?.kind === "run"; + const run = + historical && + state.selectedRunId === selection.runId && + state.selectedRunStatus === "ready" && + state.selectedRun?.summary?.runId === selection.runId + ? state.selectedRun + : undefined; + const openNode = useCallback((nodeId: string) => setInspectedNode(nodeId), []); + const closeNode = useCallback(() => setInspectedNode(undefined), []); + const collapseExplorer = useCallback(() => setExplorerCollapsed(true), []); + const restoreExplorer = useCallback(() => setExplorerCollapsed(false), []); + const select = useCallback( + (next: Selection) => { + setSelection(next); + setInspectedNode(undefined); + setExplorerOpen(false); + void selectRun(next.kind === "run" ? next.runId : undefined); + }, + [selectRun], + ); + const selectWorkflowRun = useCallback( + (runId: string) => { + if (!workflow) return; + select({ kind: "run", workflowId: workflow.workflowId, runId }); + }, + [select, workflow], + ); + const viewCurrentWorkflow = useCallback(() => { + if (!workflow) return; + select({ kind: "workflow", workflowId: workflow.workflowId }); + }, [select, workflow]); + const restoreButton = explorerCollapsed ? ( + + ) : undefined; + const runListPanel = workflow ? ( + <> + {restoreButton} + + + ) : undefined; + const showRunControls = Boolean(workflow) && (!historical || Boolean(run)); + const runControlsPanel = showRunControls ? ( + + ) : undefined; + + const liveEventDescriptorKey = + historical && inspectedNode ? `${selection.runId}:${inspectedNode}` : ""; + const inspectorOpen = Boolean(inspectedNode && (!historical || run)); + const workspaceStyle = { + "--workspace-explorer-width": `${explorerWidth}px`, + "--workspace-inspector-width": `${inspectorWidth}px`, + "--workspace-explorer-column-width": explorerCollapsed ? "0px" : `${explorerWidth}px`, + "--workspace-explorer-divider-width": "0px", + "--workspace-inspector-column-width": inspectorOpen ? `${inspectorWidth}px` : "0px", + "--workspace-inspector-divider-width": "0px", + } as CSSProperties; + + return ( +
+
+
+ +
+ Avalanche + Operator +
+
+
+ {workflow?.rootAlias || "Local operator"} + {workflow && <>/{workflow.displayName}} + {historical && <>/{selection.runId}} +
+
span]:size-[7px] [&>span]:rounded-full ${state.connection === "live" ? "[&>span]:bg-mint" : "[&>span]:bg-amber"} max-[700px]:justify-self-end connection-${state.connection}`}> + + {state.connection === "live" ? "Live" : state.connection} +
+ +
+ {state.error &&
{state.error}
} +
+ + {!explorerCollapsed && ( + + )} +
+
+ {historical ? ( + run ? ( + <> +
+ +
+ Immutable run snapshot + Current workflow changes do not alter this canvas +
+
+ + + ) : state.selectedRunId === selection.runId && + state.selectedRunStatus === "loading" ? ( + <> + {restoreButton} +
+ +

Loading run snapshot

+

Retrieving the retained topology and execution state.

+
+ + ) : state.selectedRunId === selection.runId && + state.selectedRunStatus === "error" ? ( + <> + {restoreButton} +
+ ! +

Run snapshot unavailable

+

{state.selectedRunError || "The selected run could not be loaded."}

+
+ + ) : ( + <> + {restoreButton} +
+ +

No run snapshot

+

Select the run again to load its retained topology.

+
+ + ) + ) : workflow ? ( + + ) : ( + <> + {restoreButton} +
+ +

No workflows discovered

+

Catalog changes will appear here as the operator scans configured targets.

+
+ + )} +
+
+ {inspectorOpen && ( + <> + +
+ +
+ + )} +
+
+ ); +} diff --git a/web/operator/src/Explorer.test.tsx b/web/operator/src/Explorer.test.tsx new file mode 100644 index 0000000..6f0cd4e --- /dev/null +++ b/web/operator/src/Explorer.test.tsx @@ -0,0 +1,68 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import { Explorer } from "./Explorer"; +import { CatalogSnapshotMsg, FlowInfoMsg } from "./generated/operator"; + +const orders = FlowInfoMsg.create({ + workflowId: "flows.py::orders", + displayName: "Orders", + rootAlias: "examples", + relativeFile: "flows.py", + nodeIds: ["fetch"], + graph: { fetch: { children: [] } }, + nodeTypes: { fetch: "source" }, + displayNames: { fetch: "Fetch" }, +}); +const inventory = FlowInfoMsg.create({ + ...orders, + workflowId: "inventory.py::inventory", + displayName: "Inventory", + rootAlias: "services", + relativeFile: "inventory.py", +}); + +describe("Explorer", () => { + it("lists scanned workflows directly without target or run branches", () => { + const onSelect = vi.fn(); + const view = render( + , + ); + + expect(screen.getByText("catalog r3")).toBeInTheDocument(); + expect(screen.getByRole("button", { name: /Ordersflows.py/ })).toHaveClass("active"); + expect(screen.getByRole("button", { name: /Inventoryinventory.py/ })).toBeInTheDocument(); + expect(view.container).not.toHaveTextContent("/workspace/examples"); + expect(view.container.querySelector(".target-heading")).not.toBeInTheDocument(); + expect(view.container.querySelector(".run-branches")).not.toBeInTheDocument(); + expect(view.container.querySelector(".tree-disclosure")).not.toBeInTheDocument(); + + fireEvent.click(screen.getByRole("button", { name: /Inventoryinventory.py/ })); + expect(onSelect).toHaveBeenCalledWith({ + kind: "workflow", + workflowId: inventory.workflowId, + }); + }); + + it("shows an explicit empty state when nothing was scanned", () => { + render( + , + ); + + expect(screen.getByText("No workflows scanned")).toBeInTheDocument(); + }); +}); diff --git a/web/operator/src/Explorer.tsx b/web/operator/src/Explorer.tsx new file mode 100644 index 0000000..5be3fca --- /dev/null +++ b/web/operator/src/Explorer.tsx @@ -0,0 +1,108 @@ +import { memo } from "react"; +import { PanelLeftClose } from "lucide-react"; + +import type { CatalogSnapshotMsg, FlowInfoMsg } from "./generated/operator"; + +export type Selection = + | { kind: "workflow"; workflowId: string } + | { kind: "run"; workflowId: string; runId: string }; + +interface ExplorerProps { + catalog?: CatalogSnapshotMsg; + selection?: Selection; + onSelect: (selection: Selection) => void; + onCollapse?: () => void; + open?: boolean; + collapsed?: boolean; +} + +interface WorkflowRowProps { + workflow: FlowInfoMsg; + selected: boolean; + onSelect: (selection: Selection) => void; +} + +const WorkflowRow = memo(function WorkflowRow({ + workflow, + selected, + onSelect, +}: WorkflowRowProps) { + return ( + + ); +}); + +function ExplorerView({ catalog, selection, onSelect, onCollapse, open = false, collapsed = false }: ExplorerProps) { + const collapseButton = onCollapse ? ( + + ) : null; + if (!catalog) { + return ( + + ); + } + return ( + + ); +} + +export const Explorer = memo(ExplorerView); diff --git a/web/operator/src/GraphCanvas.test.tsx b/web/operator/src/GraphCanvas.test.tsx new file mode 100644 index 0000000..2431362 --- /dev/null +++ b/web/operator/src/GraphCanvas.test.tsx @@ -0,0 +1,771 @@ +import type { ComponentType } from "react"; + +import { act, fireEvent, render, screen } from "@testing-library/react"; +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; + +interface RenderedNode { + id: string; + selected?: boolean; + position: object; + data: { + onOpen: () => void; + }; +} +interface RenderedEdge { + id: string; + source: string; + target: string; + sourceHandle?: string; + targetHandle?: string; + data?: { + lane: number; + }; + type?: string; +} + + +const graphMetrics = vi.hoisted(() => ({ + layoutCount: 0, + renderCount: 0, + seenPositions: new WeakSet(), + nodeSets: [] as RenderedNode[][], + edgeSets: [] as RenderedEdge[][], + zoom: 1, + screenToFlowPosition: vi.fn(() => ({ x: 420, y: 240 })), + setCenter: vi.fn(), +})); + +vi.mock("@xyflow/react", () => { + return { + Background: () => null, + BackgroundVariant: { Dots: "dots" }, + Controls: () => null, + Handle: ({ + id, + className, + type, + position, + }: { + id: string; + className?: string; + type: string; + position: string; + }) => ( + + ), + BaseEdge: () => null, + MarkerType: { ArrowClosed: "arrow-closed" }, + Position: { Bottom: "bottom", Left: "left", Right: "right", Top: "top" }, + useStore: () => 0, + useViewport: () => ({ x: 0, y: 0, zoom: graphMetrics.zoom }), + useReactFlow: () => ({ + screenToFlowPosition: graphMetrics.screenToFlowPosition, + setCenter: graphMetrics.setCenter, + }), + ReactFlow: ({ + nodes, + edges, + nodeTypes, + }: { + nodes: RenderedNode[]; + edges: RenderedEdge[]; + nodeTypes: Record>; + }) => { + graphMetrics.renderCount += 1; + graphMetrics.nodeSets.push(nodes); + graphMetrics.edgeSets.push(edges); + const firstPosition = nodes[0]?.position; + if (firstPosition && !graphMetrics.seenPositions.has(firstPosition)) { + graphMetrics.seenPositions.add(firstPosition); + graphMetrics.layoutCount += 1; + } + const NodeComponent = nodeTypes.workflow; + return ( +
+ {edges.length} + {nodes.map((node) => ( + + ))} +
+ ); + }, + }; +}); + +import { GraphCanvas, parseAgentDeclaration } from "./GraphCanvas"; +import { Markdown } from "./Markdown"; +import { + FlowInfoMsg, + NodeSnapshotMsg, + TraceDescriptorMsg, + WorkflowTopologyMsg, +} from "./generated/operator"; + +function metadata(field: string) { + return JSON.stringify({ + signature: { + instructions: "Current instruction.\nSecond instruction line.", + inputs: [{ name: field, type: "str" }], + outputs: [], + }, + }); +} + +function fieldSchemas(field: string) { + return JSON.stringify({ + inputs: [{ name: field, type: "str", description: "" }], + outputs: [], + }); +} + +const workflow = FlowInfoMsg.create({ + workflowId: "flow.py::demo", + displayName: "Current", + nodeIds: ["agent", "store"], + graph: { + agent: { children: ["store", "store"] }, + store: { children: [] }, + }, + nodeTypes: { agent: "step", store: "dest" }, + displayNames: { agent: "Current agent", store: "Store" }, + agentMetadataJson: { agent: metadata("current_input") }, + agentNodeIds: ["agent"], +}); + +describe("GraphCanvas", () => { + beforeEach(() => { + graphMetrics.layoutCount = 0; + graphMetrics.renderCount = 0; + graphMetrics.seenPositions = new WeakSet(); + graphMetrics.nodeSets = []; + graphMetrics.edgeSets = []; + graphMetrics.zoom = 1; + graphMetrics.screenToFlowPosition.mockClear(); + graphMetrics.setCenter.mockClear(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it("bounds Markdown source, blocks images, reveals chunks, and resets on source changes", () => { + const sourceCharacterBudget = 128; + const source = [ + "# Safe", + "[blocked](javascript:alert(1))", + "![tracker](http://127.0.0.1:9/pixel)", + "A".repeat(sourceCharacterBudget), + "SECOND_MARKER", + "B".repeat(sourceCharacterBudget), + "THIRD_MARKER", + ].join("\n\n"); + const view = render( + + {source} + , + ); + + const markdown = view.container.querySelector(".bounded-markdown"); + expect(markdown?.textContent?.length).toBeLessThanOrEqual( + sourceCharacterBudget + "Show more".length, + ); + expect(view.container.querySelector("img")).not.toBeInTheDocument(); + expect(screen.queryByText("SECOND_MARKER")).not.toBeInTheDocument(); + const blockedLink = view.container.querySelector("a"); + expect(blockedLink).toHaveTextContent("blocked"); + expect(blockedLink?.getAttribute("href") ?? "").not.toContain("javascript:"); + + fireEvent.click(screen.getByRole("button", { name: "Show more" })); + expect(screen.getByText("SECOND_MARKER")).toBeInTheDocument(); + expect(screen.queryByText("THIRD_MARKER")).not.toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Show more" })); + expect(screen.getByText("THIRD_MARKER")).toBeInTheDocument(); + + const replacement = `# Replacement\n\n${"R".repeat(sourceCharacterBudget)}\n\nRESET_TAIL`; + view.rerender( + + {replacement} + , + ); + expect(screen.getByRole("heading", { name: "Replacement" })).toBeInTheDocument(); + expect(screen.queryByText("THIRD_MARKER")).not.toBeInTheDocument(); + expect(screen.queryByText("RESET_TAIL")).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Show more" })).toBeInTheDocument(); + }); + + it("renders the current definition and keeps a historical run on recorded metadata", () => { + const view = render( + undefined} />, + ); + + expect(screen.getByText("Current agent")).toBeInTheDocument(); + expect(screen.getByText("Store")).toBeInTheDocument(); + expect(screen.getByText("current_input")).toBeInTheDocument(); + expect(screen.getByText("Current instruction.")).toHaveClass( + "node-instruction-line", + "self-stretch", + "overflow-hidden", + "line-clamp-2", + ); + expect(screen.getByText("Current instruction.")).not.toHaveClass("whitespace-nowrap"); + expect(screen.getByTestId("edge-count")).toHaveTextContent("1"); + const currentAgentCard = screen + .getByRole("button", { name: "Inspect Current agent" }) + .closest("article"); + expect(currentAgentCard).toHaveAttribute("data-node-kind", "agent"); + expect(currentAgentCard).toHaveClass("border-acid!"); + expect( + screen.getByRole("button", { name: "Inspect Store" }).closest("article"), + ).toHaveAttribute("data-node-kind", "standard"); + expect(screen.getByRole("button", { name: "Inspect Store" }).closest("article")).not.toHaveClass( + "border-acid!", + ); + + view.rerender( + undefined} + />, + ); + const historicalAgentCard = screen + .getByRole("button", { name: "Inspect Recorded agent" }) + .closest("article"); + expect(historicalAgentCard).toHaveAttribute("data-node-kind", "agent"); + expect(historicalAgentCard?.querySelector(".node-kicker")).toHaveTextContent("agent"); + + expect(screen.getByText("Recorded agent")).toBeInTheDocument(); + expect(screen.getByText("recorded_input")).toBeInTheDocument(); + expect(screen.getByText("Recorded instruction.")).toBeInTheDocument(); + expect(screen.queryByText("recorded failure")).not.toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Inspect Recorded agent" }).closest(".node-card")) + .toHaveClass("status-failed"); + expect(historicalAgentCard).toHaveClass("before:bg-agent", "border-line"); + expect(historicalAgentCard?.querySelector(".node-title")).toHaveClass("text-ink"); + expect(historicalAgentCard?.querySelector(".node-status-icon")).toHaveClass( + "lucide-x", + "size-3", + "text-failed", + ); + expect(screen.getByText("failed")).toHaveClass("text-failed"); + expect(screen.queryByText("Store")).not.toBeInTheDocument(); + expect(screen.queryByText("current_input")).not.toBeInTheDocument(); + }); + + it("distinguishes repeated invocations by stable node identity", () => { + render( + undefined} + />, + ); + + expect(screen.getByRole("button", { name: "Inspect repeat #1" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Inspect repeat #2" })).toBeInTheDocument(); + expect(screen.getByText("#1")).toBeInTheDocument(); + expect(screen.getByText("#2")).toBeInTheDocument(); + }); + + it("reuses nodes and layout for detail-only rerenders while applying status and topology changes", () => { + const onOpenNode = vi.fn(); + const topology = WorkflowTopologyMsg.create({ + nodeIds: ["agent"], + graph: { agent: { children: [] } }, + nodeTypes: { agent: "step" }, + displayNames: { agent: "Recorded agent" }, + agentFieldSchemasJson: { agent: fieldSchemas("input") }, + }); + const runningNode = NodeSnapshotMsg.create({ + nodeId: "agent", + name: "Recorded agent", + nodeType: "step", + status: "running", + startedAt: 1, + }); + const view = render( + , + ); + const initialNodes = graphMetrics.nodeSets.at(-1); + const initialPosition = initialNodes?.[0].position; + const initialOpen = initialNodes?.[0].data.onOpen; + + view.rerender( + , + ); + + expect(screen.getByText("running")).toBeInTheDocument(); + expect(graphMetrics.renderCount).toBe(1); + expect(graphMetrics.layoutCount).toBe(1); + expect(graphMetrics.nodeSets.at(-1)).toBe(initialNodes); + + view.rerender( + , + ); + + expect(screen.getByText("success")).toBeInTheDocument(); + const successCard = screen + .getByRole("button", { name: "Inspect Recorded agent" }) + .closest("article"); + expect(successCard).toHaveClass("before:bg-agent", "border-line"); + expect(successCard?.querySelector(".node-kicker")).toHaveClass("text-agent"); + expect(successCard?.querySelector(".node-title")).toHaveClass("text-ink"); + expect(successCard?.querySelector(".node-status-icon")).toHaveClass( + "lucide-check", + "size-3", + "text-success", + ); + expect(screen.getByText("success")).toHaveClass("text-success"); + expect(graphMetrics.renderCount).toBe(2); + expect(graphMetrics.layoutCount).toBe(1); + expect(graphMetrics.nodeSets.at(-1)).not.toBe(initialNodes); + expect(graphMetrics.nodeSets.at(-1)?.[0].position).toBe(initialPosition); + expect(graphMetrics.nodeSets.at(-1)?.[0].data.onOpen).toBe(initialOpen); + + view.rerender( + , + ); + + expect(screen.getByText("Renamed agent")).toBeInTheDocument(); + expect(graphMetrics.renderCount).toBe(3); + expect(graphMetrics.layoutCount).toBe(1); + view.rerender( + , + ); + + expect(screen.getByText("Store")).toBeInTheDocument(); + expect(graphMetrics.renderCount).toBe(4); + expect(graphMetrics.layoutCount).toBe(2); + const requestAnimationFrame = vi + .spyOn(window, "requestAnimationFrame") + .mockImplementation((callback) => { + callback(0); + return 0; + }); + fireEvent.click(screen.getByRole("button", { name: "Inspect Renamed agent" })); + expect(onOpenNode).toHaveBeenCalledWith("agent"); + expect(graphMetrics.screenToFlowPosition).toHaveBeenCalledOnce(); + expect(graphMetrics.setCenter).toHaveBeenCalledWith(420, 240, { + zoom: 1.2, + duration: 200, + }); + requestAnimationFrame.mockRestore(); + }); + + it("renders typed input and output lists without card instructions", () => { + const declaration = JSON.stringify({ + signature: { + instructions: + "# Triage\n\n- Keep **context**\n- Return a summary\n\n\n\n" + + "x".repeat(500) + + "\n\nGRAPH_TAIL", + inputs: [ + { + name: "record", + annotation: "Record", + description: "The record to inspect.", + }, + ], + outputs: [ + { + name: "summary", + type: "str", + description: "A concise result.", + }, + ], + }, + skills: [ + { + name: "audit", + instructions: "Check **every** field.", + modules: ["ignored"], + }, + ], + tools: [ + { + name: "lookup", + description: "Look up a record.", + implementation: { internal: true }, + }, + ], + }); + const view = render( + undefined} + />, + ); + + expect(screen.queryByRole("heading", { level: 1, name: "Triage" })).not.toBeInTheDocument(); + expect(screen.queryByText("context")).not.toBeInTheDocument(); + expect(screen.getByText("Record").tagName).toBe("CODE"); + expect(screen.getByText("str").tagName).toBe("CODE"); + const inputRow = screen.getByText("record").closest(".node-field"); + const outputRow = screen.getByText("summary").closest(".node-field"); + expect(inputRow).not.toHaveClass("node-plug-row"); + expect(outputRow).not.toHaveClass("node-plug-row"); + expect(inputRow?.closest(".node-inputs")).toBeInTheDocument(); + expect(outputRow?.closest(".node-outputs")).toBeInTheDocument(); + expect(view.container.querySelector(".node-instruction-excerpt")).not.toBeInTheDocument(); + expect(view.container.querySelector(".node-header > .node-title")).toHaveTextContent( + "Triage agent", + ); + expect(view.container).not.toHaveTextContent("[object Object]"); + expect(screen.queryByText("GRAPH_TAIL")).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: "Show more" })).not.toBeInTheDocument(); + + const parsed = parseAgentDeclaration(declaration); + expect(parsed?.skills).toEqual([ + { name: "audit", instructions: "Check **every** field." }, + ]); + expect(parsed?.tools).toEqual([ + { name: "lookup", description: "Look up a record." }, + ]); + + const handles = screen.getAllByTestId("graph-handle"); + expect(handles).toHaveLength(4); + for (const handle of handles) { + expect(handle).toHaveClass("node-handle"); + expect(handle).not.toHaveClass("endpoint-circle"); + } + expect( + handles.find((handle) => handle.getAttribute("data-handle-id") === "target-left"), + ).not.toHaveClass("node-handle-input"); + expect( + handles.find((handle) => handle.getAttribute("data-handle-id") === "target-bottom"), + ).not.toHaveClass("node-handle-input"); + expect( + handles.find((handle) => handle.getAttribute("data-handle-id") === "source-right"), + ).not.toHaveClass("node-handle-output"); + }); + + it("uses fixed title sizes across the detail zoom threshold", () => { + graphMetrics.zoom = 0.99; + const view = render( + undefined} />, + ); + + const compactCard = screen + .getByRole("button", { name: "Inspect Current agent" }) + .closest(".node-card"); + expect(compactCard).toHaveClass("node-card--compact"); + expect(compactCard).toHaveClass("justify-center", "gap-0"); + expect(compactCard?.querySelector(".node-card-details")).toBeInTheDocument(); + expect(compactCard?.querySelector(".node-kicker")).toHaveClass("node-card-meta"); + expect(compactCard?.querySelector(".node-title")).toHaveClass("text-xl"); + + graphMetrics.zoom = 1; + view.rerender( undefined} />); + const expandedCard = screen + .getByRole("button", { name: "Inspect Current agent" }) + .closest(".node-card"); + expect(expandedCard).not.toHaveClass("node-card--compact"); + expect(expandedCard?.querySelector(".node-title")).toHaveClass("text-sm"); + }); + + it("keeps failed error messages out of DAG cards", () => { + graphMetrics.zoom = 0.99; + const topology = WorkflowTopologyMsg.create({ + nodeIds: ["failed_step_1"], + graph: { failed_step_1: { children: [] } }, + nodeTypes: { failed_step_1: "step" }, + displayNames: { failed_step_1: "Failed step" }, + }); + render( + undefined} + />, + ); + + const card = screen.getByRole("button", { name: "Inspect Failed step" }).closest(".node-card"); + expect(card).toHaveClass("status-failed", "node-card--compact"); + expect(card).not.toHaveTextContent("The retained log is the error detail surface."); + }); + + + it("deduplicates dependencies and selects right or bottom source handles by depth", () => { + render( + undefined} + />, + ); + + expect(screen.getByTestId("edge-count")).toHaveTextContent("3"); + expect(graphMetrics.edgeSets.at(-1)).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "source->middle", + sourceHandle: "source-right", + targetHandle: "target-left", + type: "step", + }), + expect.objectContaining({ + id: "middle->target", + sourceHandle: "source-right", + targetHandle: "target-left", + type: "step", + }), + expect.objectContaining({ + id: "source->target", + sourceHandle: "source-bottom", + targetHandle: "target-bottom", + type: "skip", + data: { lane: 0 }, + }), + ]), + ); + }); + + it("assigns distinct lower routing lanes to skip edges", () => { + render( + undefined} + />, + ); + + expect(graphMetrics.edgeSets.at(-1)).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: "source->first", + targetHandle: "target-bottom", + type: "skip", + data: { lane: 0 }, + }), + expect.objectContaining({ + id: "source->second", + targetHandle: "target-bottom", + type: "skip", + data: { lane: 1 }, + }), + ]), + ); + }); + + it("updates running seconds without relayout and keeps completed seconds stable", () => { + vi.useFakeTimers(); + vi.setSystemTime(10_000); + graphMetrics.zoom = 0.99; + const topology = WorkflowTopologyMsg.create({ + nodeIds: ["agent"], + graph: { agent: { children: [] } }, + nodeTypes: { agent: "step" }, + displayNames: { agent: "Timed agent" }, + }); + const view = render( + undefined} + />, + ); + + expect(screen.getByText("4.5s")).toBeInTheDocument(); + const compactDuration = screen.getByText("4.5s"); + expect(compactDuration.parentElement).toHaveClass("node-card"); + expect(compactDuration).toHaveClass( + "top-3", + "right-3", + "text-sm", + "transition-[font-size]", + "duration-150", + ); + expect(screen.getByRole("button", { name: "Inspect Timed agent" }).closest(".node-card")) + .toHaveClass("status-running", "gradient-animate"); + act(() => vi.advanceTimersByTime(100)); + expect(screen.getByText("4.6s")).toBeInTheDocument(); + act(() => vi.advanceTimersByTime(900)); + expect(screen.getByText("5.5s")).toBeInTheDocument(); + expect(graphMetrics.layoutCount).toBe(1); + view.unmount(); + act(() => vi.advanceTimersByTime(7_000)); + const reentered = render( + undefined} + />, + ); + expect(screen.getByText("12.5s")).toBeInTheDocument(); + act(() => vi.advanceTimersByTime(100)); + expect(screen.getByText("12.6s")).toBeInTheDocument(); + + graphMetrics.zoom = 1; + reentered.rerender( + undefined} + />, + ); + expect(screen.getByText("2.0s")).toBeInTheDocument(); + expect(screen.getByText("2.0s")).toHaveClass("top-4", "right-4", "text-[9px]"); + expect(screen.getByRole("button", { name: "Inspect Timed agent" }).closest(".node-card")) + .toHaveClass("status-success"); + act(() => vi.advanceTimersByTime(5_000)); + expect(screen.getByText("2.0s")).toBeInTheDocument(); + expect(graphMetrics.layoutCount).toBe(2); + reentered.unmount(); + }); +}); diff --git a/web/operator/src/GraphCanvas.tsx b/web/operator/src/GraphCanvas.tsx new file mode 100644 index 0000000..635d88b --- /dev/null +++ b/web/operator/src/GraphCanvas.tsx @@ -0,0 +1,689 @@ +import { + memo, + type MouseEvent, + type ReactNode, + useCallback, + useEffect, + useMemo, + useRef, + useState, +} from "react"; +import { Check, X } from "lucide-react"; + +import { + Background, + BackgroundVariant, + BaseEdge, + Controls, + Handle, + MarkerType, + Panel, + Position, + ReactFlow, + useReactFlow, + useStore, + useViewport, + type Edge, + type EdgeProps, + type Node, + type NodeProps, +} from "@xyflow/react"; + +import type { + FlowInfoMsg, + NodeSnapshotMsg, + WorkflowTopologyMsg, +} from "./generated/operator"; +import { isUnknownRecord } from "./guards"; + +interface FieldMetadata { + name: string; + type?: string; + description?: string; +} +export interface SkillMetadata { + name: string; + instructions: string; +} + +export interface ToolMetadata { + name: string; + description: string; +} + +export interface AgentFieldSchemas { + inputs: FieldMetadata[]; + outputs: FieldMetadata[]; +} + +export interface AgentDeclaration extends AgentFieldSchemas { + instructions: string; + model?: unknown; + runtime?: unknown; + skills: SkillMetadata[]; + tools: ToolMetadata[]; +} + +interface CardData extends Record { + label: string; + nodeType: string; + isAgent: boolean; + identity?: string; + status?: string; + error?: string; + startedAt?: number; + endedAt?: number; + runningElapsedSeconds?: number; + declaration?: AgentFieldSchemas; + instructionLine?: string; + onOpen: () => void; +} + +function skills(value: unknown): SkillMetadata[] { + if (!Array.isArray(value)) return []; + return value.flatMap((item) => + isUnknownRecord(item) && typeof item.name === "string" + ? [ + { + name: item.name, + instructions: typeof item.instructions === "string" ? item.instructions : "", + }, + ] + : [], + ); +} + +function tools(value: unknown): ToolMetadata[] { + if (!Array.isArray(value)) return []; + return value.flatMap((item) => + isUnknownRecord(item) && typeof item.name === "string" + ? [ + { + name: item.name, + description: typeof item.description === "string" ? item.description : "", + }, + ] + : [], + ); +} + +function fields(value: unknown): FieldMetadata[] { + if (!Array.isArray(value)) return []; + return value.flatMap((item) => { + if (!isUnknownRecord(item) || typeof item.name !== "string") return []; + return [ + { + name: item.name, + type: + typeof item.type === "string" + ? item.type + : typeof item.annotation === "string" + ? item.annotation + : undefined, + description: + typeof item.description === "string" ? item.description : undefined, + }, + ]; + }); +} + +export function parseAgentDeclaration(raw: string | undefined): AgentDeclaration | undefined { + if (!raw) return undefined; + try { + const metadata: unknown = JSON.parse(raw); + if (!isUnknownRecord(metadata)) return undefined; + const signature = isUnknownRecord(metadata.signature) ? metadata.signature : {}; + return { + instructions: + typeof signature.instructions === "string" ? signature.instructions : "", + inputs: fields(signature.inputs), + outputs: fields(signature.outputs), + model: metadata.models, + runtime: metadata.runtime, + skills: skills(metadata.skills), + tools: tools(metadata.tools), + }; + } catch { + return undefined; + } +} + +export function parseAgentFieldSchemas(raw: string | undefined): AgentFieldSchemas | undefined { + if (!raw) return undefined; + try { + const metadata: unknown = JSON.parse(raw); + if (!isUnknownRecord(metadata)) return undefined; + return { + inputs: fields(metadata.inputs), + outputs: fields(metadata.outputs), + }; + } catch { + return undefined; + } +} +function firstInstructionLine(instructions: string | undefined): string | undefined { + const [firstLine] = instructions?.split(/\r?\n/, 1) ?? []; + const instructionLine = firstLine?.trim(); + return instructionLine || undefined; +} + + +const NODE_DETAIL_ZOOM_THRESHOLD = 1.0; +const FOCUSED_NODE_ZOOM = 1.2; + + + +const NodeDuration = memo( + ({ + startedAt, + endedAt, + runningElapsedSeconds, + running, + compact, + }: { + startedAt: number; + endedAt?: number; + running: boolean; + runningElapsedSeconds: number; + compact: boolean; + }) => { + const [nowMs, setNowMs] = useState(() => performance.now()); + const runningClock = useRef< + { startedAt: number; elapsedSeconds: number; receivedAtMs: number } | undefined + >(undefined); + const isRunning = running && endedAt === undefined; + if ( + isRunning && + (runningClock.current?.startedAt !== startedAt || + runningClock.current.elapsedSeconds !== runningElapsedSeconds) + ) { + runningClock.current = { + startedAt, + elapsedSeconds: runningElapsedSeconds, + receivedAtMs: performance.now(), + }; + } + useEffect(() => { + if (!isRunning) return; + setNowMs(performance.now()); + const interval = window.setInterval(() => setNowMs(performance.now()), 100); + return () => window.clearInterval(interval); + }, [isRunning, runningElapsedSeconds, startedAt]); + const elapsedSeconds = + endedAt !== undefined + ? Math.max(0, endedAt - startedAt) + : isRunning + ? Math.max( + 0, + (runningClock.current?.elapsedSeconds ?? runningElapsedSeconds) + + (nowMs - (runningClock.current?.receivedAtMs ?? nowMs)) / 1_000, + ) + : 0; + return ( + + {elapsedSeconds.toFixed(1)}s + + ); + }, +); +NodeDuration.displayName = "NodeDuration"; + +const WorkflowNodeCard = memo(({ data, selected }: NodeProps>) => { + const { screenToFlowPosition, setCenter } = useReactFlow(); + const { zoom } = useViewport(); + const isCompact = zoom < NODE_DETAIL_ZOOM_THRESHOLD; + const openAndFocusNode = useCallback( + (event: MouseEvent) => { + const bounds = event.currentTarget.getBoundingClientRect(); + const nodeCenter = screenToFlowPosition({ + x: bounds.left + bounds.width / 2, + y: bounds.top + bounds.height / 2, + }); + data.onOpen(); + window.requestAnimationFrame(() => { + window.requestAnimationFrame(() => { + void setCenter(nodeCenter.x, nodeCenter.y, { + zoom: FOCUSED_NODE_ZOOM, + duration: 200, + }); + }); + }); + }, + [data.onOpen, screenToFlowPosition, setCenter], + ); + const agentClass = data.isAgent + ? "node-agent before:pointer-events-none before:absolute before:inset-y-3 before:left-0 before:w-[3px] before:rounded-r-full before:bg-agent before:content-['']" + : ""; + const statusColorClass = + data.status === "success" + ? "text-success" + : data.status === "failed" + ? "text-failed" + : "text-muted"; + const statusClass = + data.status === "success" + ? "status-success" + : data.status === "failed" + ? "status-failed" + : data.status === "running" + ? "status-running gradient-animate border-[3px]" + : "blueprint"; + return ( +
+ + +
+ ); +}); +WorkflowNodeCard.displayName = "WorkflowNodeCard"; + +interface SkipEdgeData extends Record { + lane: number; +} + +type SkipEdge = Edge; + +const SKIP_EDGE_CLEARANCE = 56; +const SKIP_EDGE_LANE_GAP = 32; + +const SkipEdge = memo( + ({ + data, + markerEnd, + sourceX, + sourceY, + style, + targetX, + targetY, + }: EdgeProps) => { + const graphBottom = useStore((state) => + Math.max( + ...Array.from( + state.nodeLookup.values(), + (node) => node.internals.positionAbsolute.y + (node.measured.height ?? 0), + ), + ), + ); + if (data === undefined) { + throw new Error("Skip edge is missing its routing lane"); + } + const routeY = graphBottom + SKIP_EDGE_CLEARANCE + data.lane * SKIP_EDGE_LANE_GAP; + const path = `M ${sourceX},${sourceY} L ${sourceX},${routeY} L ${targetX},${routeY} L ${targetX},${targetY}`; + + return ; + }, +); +SkipEdge.displayName = "SkipEdge"; + +const NODE_TYPES = { workflow: WorkflowNodeCard }; +const EDGE_TYPES = { skip: SkipEdge }; +const FIT_VIEW_OPTIONS = { padding: 0.24 }; + + +function invocationIdentity(nodeId: string, label: string): string { + const suffix = nodeId.startsWith(`${label}_`) ? nodeId.slice(label.length + 1) : ""; + return suffix && /^\d+$/.test(suffix) ? `#${suffix}` : nodeId; +} + +type TopologyView = Pick< + WorkflowTopologyMsg, + "nodeIds" | "graph" | "nodeTypes" | "displayNames" | "agentInstructionLines" +>; + +interface GraphLayout { + edges: Edge[]; + positions: Record; +} + +function createGraphLayout(topology: Pick): GraphLayout { + const incoming = Object.fromEntries(topology.nodeIds.map((nodeId) => [nodeId, 0])); + for (const edges of Object.values(topology.graph)) { + for (const child of edges.children) incoming[child] = (incoming[child] ?? 0) + 1; + } + const depths: Record = {}; + const queue = topology.nodeIds.filter((nodeId) => incoming[nodeId] === 0); + for (const nodeId of queue) depths[nodeId] = 0; + for (let index = 0; index < queue.length; index += 1) { + const parent = queue[index]; + for (const child of topology.graph[parent]?.children ?? []) { + depths[child] = Math.max(depths[child] ?? 0, depths[parent] + 1); + incoming[child] -= 1; + if (incoming[child] === 0) queue.push(child); + } + } + const rows: Record = {}; + for (const nodeId of topology.nodeIds) { + const depth = depths[nodeId] ?? 0; + (rows[depth] ??= []).push(nodeId); + } + const positions = Object.fromEntries( + Object.entries(rows).flatMap(([depth, nodeIds]) => + nodeIds.map((nodeId, row) => [ + nodeId, + { + x: Number(depth) * 500, + y: row * 220 - ((nodeIds.length - 1) * 110), + }, + ]), + ), + ); + const seen = new Set(); + const edges: Edge[] = []; + let skipEdgeLane = 0; + for (const [source, children] of Object.entries(topology.graph)) { + for (const target of children.children) { + const id = `${source}->${target}`; + if (seen.has(id)) continue; + seen.add(id); + const isSkipEdge = depths[target] !== (depths[source] ?? 0) + 1; + edges.push({ + id, + source, + target, + sourceHandle: isSkipEdge ? "source-bottom" : "source-right", + targetHandle: isSkipEdge ? "target-bottom" : "target-left", + markerEnd: { type: MarkerType.ArrowClosed }, + type: isSkipEdge ? "skip" : "step", + data: isSkipEdge ? { lane: skipEdgeLane++ } : undefined, + className: "dag-edge", + }); + } + } + return { edges, positions }; +} + +interface GraphCanvasProps { + workflow?: FlowInfoMsg; + runTopology?: WorkflowTopologyMsg; + runNodes?: NodeSnapshotMsg[]; + topLeftPanel?: ReactNode; + bottomRightPanel?: ReactNode; + selectedNodeId?: string; + onClearNode?: () => void; + onOpenNode: (nodeId: string) => void; +} + +function GraphCanvasView({ + workflow, + runTopology, + runNodes = [], + topLeftPanel, + bottomRightPanel, + selectedNodeId, + onClearNode, + onOpenNode, +}: GraphCanvasProps) { + const isCurrentWorkflow = workflow !== undefined && runTopology === undefined; + const topology = useMemo(() => { + if (runTopology) return runTopology; + if (!workflow) return undefined; + return { + nodeIds: workflow.nodeIds, + graph: workflow.graph, + nodeTypes: workflow.nodeTypes, + displayNames: workflow.displayNames, + agentInstructionLines: {}, + }; + }, [runTopology, workflow]); + const topologyNodeIds = topology?.nodeIds; + const topologyGraph = topology?.graph; + const layout = useMemo( + () => + topologyNodeIds && topologyGraph + ? createGraphLayout({ nodeIds: topologyNodeIds, graph: topologyGraph }) + : { edges: [], positions: {} }, + [topologyGraph, topologyNodeIds], + ); + const openCallbacks = useMemo( + () => + Object.fromEntries( + (topologyNodeIds ?? []).map((nodeId) => [nodeId, () => onOpenNode(nodeId)]), + ), + [onOpenNode, topologyNodeIds], + ); + const agentNodeIds = useMemo( + () => + new Set( + runTopology + ? Object.keys(runTopology.agentFieldSchemasJson) + : (workflow?.agentNodeIds ?? []), + ), + [runTopology, workflow], + ); + const nodes = useMemo(() => { + if (!topology) return []; + const runtimeNodes = Object.fromEntries(runNodes.map((node) => [node.nodeId, node])); + const labels = Object.fromEntries( + topology.nodeIds.map((nodeId) => [ + nodeId, + topology.displayNames[nodeId] || runtimeNodes[nodeId]?.name || nodeId, + ]), + ); + const labelCounts = Object.values(labels).reduce>( + (counts, label) => ({ ...counts, [label]: (counts[label] ?? 0) + 1 }), + {}, + ); + const nodes: Node[] = topology.nodeIds.map((nodeId) => { + const runtimeNode = runtimeNodes[nodeId]; + const agentDeclaration = runTopology + ? undefined + : parseAgentDeclaration(workflow?.agentMetadataJson[nodeId]); + const declaration = runTopology + ? parseAgentFieldSchemas(runTopology.agentFieldSchemasJson[nodeId]) + : agentDeclaration; + const instructionLine = runTopology + ? runTopology.agentInstructionLines[nodeId] || undefined + : firstInstructionLine(agentDeclaration?.instructions); + return { + id: nodeId, + selected: nodeId === selectedNodeId, + type: "workflow", + position: layout.positions[nodeId], + data: { + label: labels[nodeId], + identity: + labelCounts[labels[nodeId]] > 1 + ? invocationIdentity(nodeId, labels[nodeId]) + : undefined, + nodeType: topology.nodeTypes[nodeId] || runtimeNode?.nodeType || "step", + isAgent: agentNodeIds.has(nodeId), + status: runtimeNode?.status, + error: runtimeNode?.error, + startedAt: runtimeNode?.startedAt || undefined, + endedAt: runtimeNode?.endedAt || undefined, + runningElapsedSeconds: runtimeNode?.runningElapsedSeconds ?? 0, + declaration, + instructionLine, + onOpen: openCallbacks[nodeId], + }, + }; + }); + return nodes; + }, [agentNodeIds, layout.positions, openCallbacks, runNodes, runTopology, selectedNodeId, topology, workflow]); + + return ( + + {topLeftPanel && ( + + {topLeftPanel} + + )} + {bottomRightPanel && ( + + {bottomRightPanel} + + )} + + + + ); +} + +function sameRunNodeState( + left: readonly NodeSnapshotMsg[] | undefined, + right: readonly NodeSnapshotMsg[] | undefined, +) { + if (left === right) return true; + if ((left?.length ?? 0) !== (right?.length ?? 0)) return false; + return (left ?? []).every((node, index) => { + const other = right?.[index]; + return ( + other !== undefined && + node.nodeId === other.nodeId && + node.name === other.name && + node.nodeType === other.nodeType && + node.status === other.status && + node.error === other.error && + node.startedAt === other.startedAt && + node.endedAt === other.endedAt + ); + }); +} + +export const GraphCanvas = memo( + GraphCanvasView, + (left, right) => + left.workflow === right.workflow && + left.runTopology === right.runTopology && + left.topLeftPanel === right.topLeftPanel && + left.bottomRightPanel === right.bottomRightPanel && + left.selectedNodeId === right.selectedNodeId && + left.onClearNode === right.onClearNode && + left.onOpenNode === right.onOpenNode && + sameRunNodeState(left.runNodes, right.runNodes), +); diff --git a/web/operator/src/Inspector.test.tsx b/web/operator/src/Inspector.test.tsx new file mode 100644 index 0000000..0caabae --- /dev/null +++ b/web/operator/src/Inspector.test.tsx @@ -0,0 +1,602 @@ +import { act, fireEvent, render, screen, waitFor, within } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import type { AgentEventDescriptorPage, OperatorApi } from "./api"; +import { + DescriptorPageOrder, + type AgentEventDescriptorMsg, + type CatalogSnapshotMsg, + type FlowInfoMsg, + type RunSnapshotMsg, +} from "./generated/operator"; +import { Inspector } from "./Inspector"; + +const declaration = JSON.stringify({ + signature: { + name: "Analyze", + instructions: "# Investigate\nUse **retained evidence**.", + inputs: [{ name: "question", annotation: "str", description: "Question to answer" }], + outputs: [{ name: "answer", annotation: "str", description: "Final answer" }], + }, + runtime: { timeout: 30 }, + models: { main: "reasoning-model" }, + skills: [{ name: "Research", instructions: "Search **carefully**." }], + tools: [{ name: "lookup", description: "Reads `trusted` sources." }], +}); + +const fieldSchemas = JSON.stringify({ + inputs: [{ name: "question", annotation: "str", description: "Question to answer" }], + outputs: [{ name: "answer", annotation: "str", description: "Final answer" }], +}); + +const workflow: FlowInfoMsg = { + name: "agent_flow", + filePath: "agent_flow.py", + nodeIds: ["agent_1"], + graph: { agent_1: { children: [] } }, + nodeTypes: { agent_1: "step" }, + displayNames: { agent_1: "Agent" }, + cron: "", + nextRunAt: 0, + lastRunAt: 0, + workflowId: "agent_flow.py::agent_flow", + displayName: "agent_flow", + rootAlias: "examples", + relativeFile: "agent_flow.py", + builderSymbol: "agent_flow", + agentNodeIds: ["agent_1"], + agentMetadataJson: { agent_1: declaration }, + webhookPath: "", + webhookUrl: "", + webhookActive: false, +}; + +const run: RunSnapshotMsg = { + operatorInstanceId: "operator-1", + asOfSequence: "9", + summary: { + runId: "run-1", + flowName: "agent_flow", + status: "success", + startedAt: 10, + endedAt: 11, + triggeredAt: 9, + triggeredBy: "manual", + workflowId: workflow.workflowId, + workflowDisplayName: workflow.displayName, + createdSequence: "2", + revision: "9", + }, + nodes: [ + { + nodeId: "agent_1", + name: "Agent", + nodeType: "step", + status: "success", + startedAt: 10, + endedAt: 11, + trace: { + status: "completed", + revision: "4", + available: true, + complete: true, + eventCount: "2", + sizeBytes: "256", + latestEventSequence: "2", + header: { + status: "completed", + model: "main-model", + subModel: "sub-model", + iterations: "2", + maxIterations: "4", + durationMs: "125", + usageJson: '{"input_tokens":12}', + telemetryJson: '{"trace_id":"trace-1"}', + }, + }, + revision: "4", + eventPageToken: "events", + }, + ], + latestLogSequence: "0", + logPageToken: "logs", + topology: { + nodeIds: ["agent_1"], + graph: { agent_1: { children: [] } }, + nodeTypes: { agent_1: "step" }, + displayNames: { agent_1: "Agent" }, + agentFieldSchemasJson: { agent_1: fieldSchemas }, + agentInstructionLines: { agent_1: "Answer the question." }, + }, +}; + +function event( + sequence: number, + kind: AgentEventDescriptorMsg["eventKind"] = "iteration.recorded", +): AgentEventDescriptorMsg { + return { + eventSequence: String(sequence), + sizeBytes: "64", + bodyToken: `event-${sequence}`, + invocationId: "invocation-1", + eventKind: kind, + iteration: kind === "iteration.recorded" ? sequence : undefined, + durationMs: kind === "iteration.recorded" ? "10" : undefined, + toolCount: kind === "iteration.recorded" ? 1 : 0, + predictCount: kind === "iteration.recorded" ? 1 : 0, + error: false, + }; +} + + +function eventPage( + records: AgentEventDescriptorMsg[], + nextPageToken = "", + nextCursor = records.at(-1)?.eventSequence ?? "0", +): AgentEventDescriptorPage { + return { + operatorInstanceId: run.operatorInstanceId, + asOfSequence: run.asOfSequence, + runId: run.summary!.runId, + nodeId: "agent_1", + records, + nextPageToken, + nextCursor, + }; +} + +function operatorApi(): OperatorApi { + const events = [event(1, "run.started"), event(2, "run.succeeded")]; + return { + getCatalog: async (): Promise => { + throw new Error("unused"); + }, + loadBaseline: async () => { + throw new Error("unused"); + }, + getLatestRunSnapshot: async () => run, + streamUpdates: async function* () { + return; + }, + listAgentEventPage: async () => eventPage(events), + listLogPage: async () => ({ + operatorInstanceId: run.operatorInstanceId, + asOfSequence: run.asOfSequence, + records: [], + nextPageToken: "", + nextCursor: "0", + }), + readJsonDetail: async (token) => + token === "event-1" + ? { inputs: { question: "Why?" } } + : { outputs: { answer: "Because." } }, + readTextDetail: async (token) => token, + startRun: async () => "unused", + cancelRun: async () => undefined, + }; +} + +function deferred() { + let resolve!: (value: T) => void; + let reject!: (reason: unknown) => void; + const promise = new Promise((next, fail) => { + resolve = next; + reject = fail; + }); + return { promise, reject, resolve }; +} + +describe("Inspector", () => { + it("renders declaration instructions, skills, and tools as Markdown without object dumps", () => { + const view = render( + undefined} + />, + ); + + expect(screen.getByRole("heading", { name: "Investigate" })).toBeInTheDocument(); + expect(screen.getByText("retained evidence").tagName).toBe("STRONG"); + expect(screen.getByText("Research")).toBeInTheDocument(); + expect(screen.getByText("carefully").tagName).toBe("STRONG"); + expect(screen.getByText("lookup")).toBeInTheDocument(); + expect(screen.getByText("trusted").tagName).toBe("CODE"); + expect(view.container).not.toHaveTextContent('"skills"'); + expect(view.container.querySelector(".inspector-body-full")).toBeInTheDocument(); + }); + + it("keeps Overview hydration-free and gives the active panel the full-height classes", () => { + const api = operatorApi(); + const listAgentEventPage = vi.fn(api.listAgentEventPage); + const listLogPage = vi.fn(api.listLogPage); + const readJsonDetail = vi.fn(api.readJsonDetail); + const view = render( + undefined} + />, + ); + + expect(listAgentEventPage).not.toHaveBeenCalled(); + expect(listLogPage).not.toHaveBeenCalled(); + expect(readJsonDetail).not.toHaveBeenCalled(); + expect(view.container.querySelector(".inspector-run")).toHaveClass("inspector"); + expect(view.container.querySelector(".inspector-body")).toHaveClass("inspector-body-full"); + expect(view.container.querySelector(".inspector-overview")).toHaveClass("inspector-panel"); + expect(screen.queryByText("Revision")).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: "logs" })).not.toBeInTheDocument(); + }); + + it("shows immediate Inputs loading, cancels superseded detail, and renders the retained root directly", async () => { + const inputDetail = deferred(); + const outputDetail = deferred(); + let inputSignal: AbortSignal | undefined; + const readJsonDetail = vi.fn((token: string, signal?: AbortSignal) => { + if (token === "event-1") { + inputSignal = signal; + return inputDetail.promise; + } + return outputDetail.promise; + }); + render( + undefined} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "inputs" })); + expect(screen.getByRole("status")).toHaveTextContent("Loading retained inputs"); + await waitFor(() => expect(inputSignal).toBeDefined()); + + fireEvent.click(screen.getByRole("button", { name: "output" })); + expect(inputSignal!.aborted).toBe(true); + expect(screen.getByRole("status")).toHaveTextContent("Loading retained output"); + await act(async () => { + outputDetail.resolve({ outputs: { answer: "fresh output" } }); + await outputDetail.promise; + }); + const outputTree = await screen.findByRole("tree", { name: "JSON value" }); + expect(within(outputTree).getByText("fresh output")).toBeInTheDocument(); + expect(within(outputTree).getByText("answer")).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Object/i })).not.toBeInTheDocument(); + + await act(async () => { + inputDetail.resolve({ inputs: { question: "stale input" } }); + await inputDetail.promise; + }); + expect(screen.queryByText("stale input")).not.toBeInTheDocument(); + expect(screen.getByText("fresh output")).toBeInTheDocument(); + }); + + it("renders the empty Inputs copy only after an authoritative empty page", async () => { + const api = operatorApi(); + const readJsonDetail = vi.fn(api.readJsonDetail); + render( + eventPage([]), + readJsonDetail, + }} + workflow={workflow} + run={run} + nodeId="agent_1" + onClose={() => undefined} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "inputs" })); + expect(screen.getByRole("status")).toHaveTextContent("Loading retained inputs"); + expect(await screen.findByText("No retained inputs are available.")).toBeInTheDocument(); + expect(screen.queryByRole("status")).not.toBeInTheDocument(); + expect(readJsonDetail).not.toHaveBeenCalled(); + }); + + it("retains the Inputs run.started event while forward paging exceeds the descriptor window", async () => { + const pages = Array.from({ length: 6 }, (_, pageIndex) => + Array.from({ length: 100 }, (_, index) => { + const sequence = pageIndex * 100 + index + 1; + return event(sequence, sequence === 1 ? "run.started" : "iteration.recorded"); + }), + ); + const listAgentEventPage = vi.fn(async (request) => { + const pageIndex = + request.pageToken === "events" ? 0 : Number(request.pageToken.replace("events-", "")) - 1; + return eventPage( + pages[pageIndex], + pageIndex < pages.length - 1 ? `events-${pageIndex + 2}` : "", + String((pageIndex + 1) * 100), + ); + }); + render( + undefined} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "inputs" })); + expect(await screen.findByText("Why?")).toBeInTheDocument(); + for (let pageIndex = 1; pageIndex < pages.length; pageIndex += 1) { + fireEvent.click(screen.getByRole("button", { name: "Load more events" })); + await waitFor(() => expect(listAgentEventPage).toHaveBeenCalledTimes(pageIndex + 1)); + if (pageIndex < pages.length - 1) { + await waitFor(() => + expect(screen.getByRole("button", { name: "Load more events" })).toBeEnabled(), + ); + } + } + expect(listAgentEventPage).toHaveBeenLastCalledWith( + expect.objectContaining({ + afterEventSequence: "500", + beforeEventSequence: "0", + order: DescriptorPageOrder.FORWARD, + }), + expect.any(AbortSignal), + ); + await waitFor(() => + expect(screen.queryByRole("button", { name: "Load more events" })).not.toBeInTheDocument(), + ); + expect(screen.getByText("Why?")).toBeInTheDocument(); + }); + + it("retains the terminal Output value event while backward paging exceeds the descriptor window", async () => { + const pages = Array.from({ length: 6 }, (_, pageIndex) => + Array.from({ length: 100 }, (_, index) => { + const sequence = 600 - pageIndex * 100 - index; + return event(sequence, sequence === 600 ? "run.succeeded" : "iteration.recorded"); + }), + ); + const listAgentEventPage = vi.fn(async (request) => { + const pageIndex = + request.pageToken === "events" ? 0 : Number(request.pageToken.replace("events-", "")) - 1; + return eventPage( + pages[pageIndex], + pageIndex < pages.length - 1 ? `events-${pageIndex + 2}` : "", + String(501 - pageIndex * 100), + ); + }); + render( + undefined} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "output" })); + expect(await screen.findByText("Because.")).toBeInTheDocument(); + for (let pageIndex = 1; pageIndex < pages.length; pageIndex += 1) { + fireEvent.click(screen.getByRole("button", { name: "Load more events" })); + await waitFor(() => expect(listAgentEventPage).toHaveBeenCalledTimes(pageIndex + 1)); + if (pageIndex < pages.length - 1) { + await waitFor(() => + expect(screen.getByRole("button", { name: "Load more events" })).toBeEnabled(), + ); + } + } + expect(listAgentEventPage).toHaveBeenLastCalledWith( + expect.objectContaining({ + afterEventSequence: "0", + beforeEventSequence: "101", + order: DescriptorPageOrder.NEWEST_FIRST, + }), + expect.any(AbortSignal), + ); + await waitFor(() => + expect(screen.queryByRole("button", { name: "Load more events" })).not.toBeInTheDocument(), + ); + expect(screen.getByText("Because.")).toBeInTheDocument(); + }); + + it("cancels an inactive descriptor page and suppresses its late completion", async () => { + const pending = deferred(); + let pageSignal: AbortSignal | undefined; + const api: OperatorApi = { + ...operatorApi(), + listAgentEventPage: (_request, signal) => { + pageSignal = signal; + return pending.promise; + }, + }; + render( + undefined} />, + ); + + fireEvent.click(screen.getByRole("button", { name: "trace" })); + expect(await screen.findByText("Loading retained trace…")).toBeInTheDocument(); + await waitFor(() => expect(pageSignal).toBeDefined()); + fireEvent.click(screen.getByRole("button", { name: "overview" })); + expect(pageSignal!.aborted).toBe(true); + + await act(async () => { + pending.resolve(eventPage([event(99)])); + await pending.promise; + }); + expect(screen.queryByText("99 retained turns")).not.toBeInTheDocument(); + }); + + it("projects trace header and progressively hydrated turns into one hierarchy", async () => { + const firstTurnBody = deferred(); + const listAgentEventPage = vi.fn(async (request) => + request.pageToken === "events" + ? eventPage([event(1), event(2)], "events-next", "2") + : eventPage([event(3)], "", "3"), + ); + const readJsonDetail = vi.fn((token: string) => + token === "event-1" + ? firstTurnBody.promise + : Promise.resolve({ reasoning: `reasoning-${token}`, output: `output-${token}` }), + ); + const api = { ...operatorApi(), listAgentEventPage, readJsonDetail }; + const view = render( + undefined} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "trace" })); + const trace = await screen.findByRole("heading", { name: "RunTrace" }); + const panel = trace.closest("section")!; + expect(within(panel).getByText("main-model")).toBeInTheDocument(); + fireEvent.click(within(panel).getByRole("button", { name: "Expand telemetry" })); + expect(within(panel).getByText("trace_id")).toBeInTheDocument(); + expect(view.container.querySelector(".turn-list")).not.toBeInTheDocument(); + expect(view.container.querySelector(".turn-row")).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Turn 1/ })).not.toBeInTheDocument(); + + expect(await within(panel).findByText("2 retained turns")).toBeInTheDocument(); + fireEvent.click(within(panel).getByRole("button", { name: "Expand turns" })); + await waitFor(() => expect(listAgentEventPage).toHaveBeenCalledTimes(2)); + expect(listAgentEventPage).toHaveBeenLastCalledWith( + expect.objectContaining({ + pageToken: "events-next", + afterEventSequence: "2", + beforeEventSequence: "0", + order: DescriptorPageOrder.FORWARD, + }), + expect.any(AbortSignal), + ); + expect(await within(panel).findByRole("button", { name: "Expand 2" })).toBeInTheDocument(); + + fireEvent.click(within(panel).getByRole("button", { name: "Expand 0" })); + expect(await within(panel).findByText("Loading retained turn…")).toBeInTheDocument(); + await act(async () => { + firstTurnBody.resolve({ reasoning: "reasoning-one", code: "print('one')" }); + await firstTurnBody.promise; + }); + expect(await within(panel).findByText("reasoning-one")).toBeInTheDocument(); + expect(within(panel).getByRole("button", { name: "Collapse turns" })).toBeInTheDocument(); + + view.rerender( + undefined} + />, + ); + expect(within(panel).getByRole("button", { name: "Collapse 0" })).toBeInTheDocument(); + expect(within(panel).getByText("reasoning-one")).toBeInTheDocument(); + expect(await within(panel).findByRole("button", { name: "Expand 3" })).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Following live" })).toBeInTheDocument(); + }); + + it("aborts deferred trace detail hydration when the Inspector unmounts", async () => { + const turnDetail = deferred(); + let detailSignal: AbortSignal | undefined; + const readJsonDetail = vi.fn((_token: string, signal?: AbortSignal) => { + detailSignal = signal; + return turnDetail.promise; + }); + const view = render( + eventPage([event(1)]), + readJsonDetail, + }} + workflow={workflow} + run={run} + nodeId="agent_1" + onClose={() => undefined} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "trace" })); + expect(await screen.findByText("1 retained turn")).toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Expand turns" })); + fireEvent.click(screen.getByRole("button", { name: "Expand 0" })); + await waitFor(() => expect(detailSignal).toBeDefined()); + + view.unmount(); + expect(detailSignal!.aborted).toBe(true); + await act(async () => { + turnDetail.resolve({ reasoning: "too late" }); + await turnDetail.promise; + }); + expect(readJsonDetail).toHaveBeenCalledTimes(1); + }); + + it("evicts trace bodies by reported bytes and rejects an individually oversized body", async () => { + const records = Array.from({ length: 6 }, (_, index) => ({ + ...event(index + 1), + sizeBytes: index === 5 ? String(9 * 1024 * 1024) : String(2 * 1024 * 1024), + })); + const readJsonDetail = vi.fn(async (token: string) => ({ body: `body-${token}` })); + render( + eventPage(records), + readJsonDetail, + }} + workflow={workflow} + run={run} + nodeId="agent_1" + onClose={() => undefined} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "trace" })); + fireEvent.click(await screen.findByRole("button", { name: "Expand turns" })); + for (let index = 0; index < 5; index += 1) { + fireEvent.click(screen.getByRole("button", { name: `Expand ${index}` })); + await waitFor(() => + expect(readJsonDetail.mock.calls.filter(([token]) => token === `event-${index + 1}`)).toHaveLength(1), + ); + expect(await screen.findByText(`body-event-${index + 1}`)).toBeInTheDocument(); + } + + fireEvent.click(screen.getByRole("button", { name: "Collapse 0" })); + fireEvent.click(screen.getByRole("button", { name: "Expand 0" })); + await waitFor(() => + expect(readJsonDetail.mock.calls.filter(([token]) => token === "event-1")).toHaveLength(2), + ); + + fireEvent.click(screen.getByRole("button", { name: "Expand 5" })); + expect(await screen.findByText("Unavailable · Turn detail exceeds the browser detail limit.")).toBeInTheDocument(); + }); + + + it("surfaces bounded trace page failures without mounting a selector", async () => { + render( + { + throw new Error("trace page failed"); + }, + }} + workflow={workflow} + run={run} + nodeId="agent_1" + onClose={() => undefined} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "trace" })); + expect(await screen.findByRole("alert")).toHaveTextContent("trace page failed"); + expect(document.querySelector(".turn-list")).not.toBeInTheDocument(); + }); +}); diff --git a/web/operator/src/Inspector.tsx b/web/operator/src/Inspector.tsx new file mode 100644 index 0000000..64ae021 --- /dev/null +++ b/web/operator/src/Inspector.tsx @@ -0,0 +1,795 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { X } from "lucide-react"; + +import type { OperatorApi } from "./api"; +import { + boundDescriptors, + DESCRIPTOR_PAGE_SIZE, + DETAIL_CACHE_MAX_BYTES, + type DescriptorPageState, + measuredByteCost, + mergeDescriptorPage, + SCROLL_LOAD_THRESHOLD_PX, +} from "./detailProjection"; +import { parseAgentDeclaration, parseAgentFieldSchemas } from "./GraphCanvas"; +import { + DescriptorPageOrder, + type AgentEventDescriptorMsg, + type FlowInfoMsg, + type NodeSnapshotMsg, + type RunSnapshotMsg, +} from "./generated/operator"; +import { isUnknownRecord } from "./guards"; +import { Markdown } from "./Markdown"; +import { ValueView } from "./ValueView"; + +interface InspectorProps { + api: OperatorApi; + workflow?: FlowInfoMsg; + run?: RunSnapshotMsg; + nodeId?: string; + liveEvents?: AgentEventDescriptorMsg[]; + onClose: () => void; +} + +type RunTab = "overview" | "inputs" | "output" | "trace"; +type DetailFormat = "json"; + + +interface ScopedResult { + key: string; + value: T; +} + +interface DetailCacheEntry { + value: unknown; + byteCost: number; +} + +interface InputOutputState { + key: string; + status: "loading" | "ready" | "error"; + error?: string; +} + +const DETAIL_CACHE_MAX_ENTRIES = 8; + +const EMPTY_EVENTS: AgentEventDescriptorMsg[] = []; +const EMPTY_EVENT_PAGE: DescriptorPageState = { + records: EMPTY_EVENTS, + nextPageToken: "", + nextCursor: "0", +}; + + +function parseRetainedJson(value: string | undefined) { + if (!value) return undefined; + try { + return JSON.parse(value) as unknown; + } catch { + return undefined; + } +} + +function eventPayload(value: unknown): Record | undefined { + if (!isUnknownRecord(value)) return undefined; + return isUnknownRecord(value.data) ? value.data : value; +} + +function eventSummary(event: AgentEventDescriptorMsg) { + return { + event: event.eventKind, + event_sequence: event.eventSequence, + invocation_id: event.invocationId, + iteration: event.iteration, + duration_ms: event.durationMs, + tool_count: event.toolCount, + predict_count: event.predictCount, + failed: event.error, + }; +} + +export function Inspector({ + api, + workflow, + run, + nodeId, + liveEvents = EMPTY_EVENTS, + onClose, +}: InspectorProps) { + const [tabSelection, setTabSelection] = useState<{ scope: string; tab: RunTab }>(); + const [eventPage, setEventPage] = + useState>(EMPTY_EVENT_PAGE); + const [eventPageScope, setEventPageScope] = useState(); + const [pageError, setPageError] = useState>(); + const [pageLoading, setPageLoading] = useState(false); + const [following, setFollowing] = useState(true); + const [cacheVersion, setCacheVersion] = useState(0); + const [detailErrors, setDetailErrors] = useState>({}); + const [detailLoadingVersion, setDetailLoadingVersion] = useState(0); + const [inputOutputState, setInputOutputState] = useState(); + + const detailCache = useRef(new Map()); + const detailLoading = useRef(new Set()); + const detailControllers = useRef(new Set()); + const pageController = useRef(null); + const pageRequestInFlight = useRef(false); + const pageGeneration = useRef(0); + const detailGeneration = useRef(0); + const traceScrollElement = useRef(null); + const tabRef = useRef("overview"); + + const node: NodeSnapshotMsg | undefined = run?.nodes.find((item) => item.nodeId === nodeId); + const runId = run?.summary?.runId; + const operatorInstanceId = run?.operatorInstanceId ?? ""; + const asOfSequence = run?.asOfSequence ?? ""; + const eventPageToken = node?.eventPageToken ?? ""; + const hasRunNode = Boolean(run && node); + const selectionScope = `${operatorInstanceId}\0${runId ?? ""}\0${nodeId ?? ""}`; + const descriptorScope = `${selectionScope}\0${asOfSequence}\0${eventPageToken}`; + const tab = tabSelection?.scope === selectionScope ? tabSelection.tab : "overview"; + const pageKey = `${descriptorScope}\0${tab}`; + const eventPageOrder = + tab === "output" ? DescriptorPageOrder.NEWEST_FIRST : DescriptorPageOrder.FORWARD; + const activeEventPage = eventPageScope === pageKey ? eventPage : EMPTY_EVENT_PAGE; + const workflowDeclaration = run + ? undefined + : parseAgentDeclaration(workflow?.agentMetadataJson[nodeId ?? ""]); + const runFieldSchemas = run + ? parseAgentFieldSchemas(run.topology?.agentFieldSchemasJson[nodeId ?? ""]) + : undefined; + + tabRef.current = tab; + const abortDetailHydration = useCallback(() => { + detailGeneration.current += 1; + for (const controller of detailControllers.current) controller.abort(); + detailControllers.current.clear(); + detailLoading.current.clear(); + }, []); + + useEffect( + () => () => { + abortDetailHydration(); + }, + [abortDetailHydration], + ); + + function closeInspector() { + abortDetailHydration(); + onClose(); + } + + function cacheKey(format: DetailFormat, token: string) { + return `${format}\0${token}`; + } + + function storeCachedDetail(key: string, value: unknown, reportedSize?: string) { + const byteCost = measuredByteCost(value, reportedSize); + if (byteCost > DETAIL_CACHE_MAX_BYTES) return false; + detailCache.current.delete(key); + detailCache.current.set(key, { value, byteCost }); + let cachedBytes = 0; + for (const entry of detailCache.current.values()) cachedBytes += entry.byteCost; + while ( + detailCache.current.size > DETAIL_CACHE_MAX_ENTRIES || + cachedBytes > DETAIL_CACHE_MAX_BYTES + ) { + const oldest = detailCache.current.entries().next().value as + | [string, DetailCacheEntry] + | undefined; + if (!oldest) break; + detailCache.current.delete(oldest[0]); + cachedBytes -= oldest[1].byteCost; + } + setCacheVersion((current) => current + 1); + return true; + } + + function loadMoreEvents() { + if (!activeEventPage.nextPageToken || !nodeId || !runId || pageRequestInFlight.current) return; + pageController.current?.abort(); + const generation = ++pageGeneration.current; + const controller = new AbortController(); + pageController.current = controller; + pageRequestInFlight.current = true; + setPageError(undefined); + setPageLoading(true); + void api + .listAgentEventPage( + { + pageToken: activeEventPage.nextPageToken, + afterEventSequence: + eventPageOrder === DescriptorPageOrder.FORWARD ? activeEventPage.nextCursor : "0", + beforeEventSequence: + eventPageOrder === DescriptorPageOrder.NEWEST_FIRST ? activeEventPage.nextCursor : "0", + pageSize: DESCRIPTOR_PAGE_SIZE, + order: eventPageOrder, + expectedOperatorInstanceId: operatorInstanceId, + expectedAsOfSequence: asOfSequence, + expectedRunId: runId, + expectedNodeId: nodeId, + }, + controller.signal, + ) + .then((page) => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + setEventPage((current) => + mergeDescriptorPage( + current, + page, + (event) => event.eventSequence, + eventPageOrder === DescriptorPageOrder.FORWARD ? "newer" : "older", + valueEvent ? [valueEvent.eventSequence] : [], + ), + ); + }) + .catch((error: unknown) => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + setPageError({ + key: pageKey, + value: error instanceof Error ? error.message : "Events unavailable", + }); + }) + .finally(() => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + pageRequestInFlight.current = false; + setPageLoading(false); + }); + } + + + useEffect(() => { + setTabSelection({ scope: selectionScope, tab: "overview" }); + }, [selectionScope]); + + useEffect(() => { + pageController.current?.abort(); + pageRequestInFlight.current = false; + abortDetailHydration(); + pageGeneration.current += 1; + setEventPage(EMPTY_EVENT_PAGE); + setEventPageScope(undefined); + setPageError(undefined); + setPageLoading(false); + setFollowing(true); + setDetailErrors({}); + setInputOutputState(undefined); + detailCache.current.clear(); + detailLoading.current.clear(); + }, [abortDetailHydration, api, descriptorScope]); + + useEffect(() => { + abortDetailHydration(); + setDetailLoadingVersion((current) => current + 1); + }, [abortDetailHydration, descriptorScope, tab]); + + useEffect(() => { + pageController.current?.abort(); + pageRequestInFlight.current = false; + const generation = ++pageGeneration.current; + setEventPage(EMPTY_EVENT_PAGE); + setEventPageScope(undefined); + setPageError(undefined); + setPageLoading(false); + if (!hasRunNode || !nodeId || !runId || tab === "overview") return; + + const controller = new AbortController(); + pageController.current = controller; + if (!eventPageToken) { + setEventPageScope(pageKey); + return () => controller.abort(); + } + + pageRequestInFlight.current = true; + setPageLoading(true); + void api + .listAgentEventPage( + { + pageToken: eventPageToken, + afterEventSequence: "0", + beforeEventSequence: "0", + pageSize: DESCRIPTOR_PAGE_SIZE, + order: eventPageOrder, + expectedOperatorInstanceId: operatorInstanceId, + expectedAsOfSequence: asOfSequence, + expectedRunId: runId, + expectedNodeId: nodeId, + }, + controller.signal, + ) + .then((page) => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + setEventPage(page); + setEventPageScope(pageKey); + }) + .catch((error: unknown) => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + setPageError({ + key: pageKey, + value: error instanceof Error ? error.message : "Events unavailable", + }); + }) + .finally(() => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + pageRequestInFlight.current = false; + setPageLoading(false); + }); + return () => { + controller.abort(); + if (pageController.current === controller) pageRequestInFlight.current = false; + }; + }, [ + api, + asOfSequence, + descriptorScope, + eventPageOrder, + eventPageToken, + hasRunNode, + nodeId, + operatorInstanceId, + pageKey, + runId, + tab, + ]); + + const combinedEvents = useMemo(() => { + const bySequence = new Map(); + const liveSequences = new Set(); + for (const event of activeEventPage.records) bySequence.set(event.eventSequence, event); + for (const event of liveEvents) { + bySequence.set(event.eventSequence, event); + liveSequences.add(event.eventSequence); + } + return boundDescriptors( + bySequence, + (event) => event.eventSequence, + eventPageOrder === DescriptorPageOrder.FORWARD ? "newer" : "older", + liveSequences, + ); + }, [activeEventPage.records, eventPageOrder, liveEvents]); + + const turns = useMemo( + () => combinedEvents.filter((event) => event.eventKind === "iteration.recorded"), + [combinedEvents], + ); + + + const valueEvent = useMemo(() => { + if (tab !== "inputs" && tab !== "output") return undefined; + const kind = tab === "inputs" ? "run.started" : "run.succeeded"; + return [...combinedEvents].reverse().find((event) => event.eventKind === kind); + }, [combinedEvents, tab]); + const valueDetailKey = valueEvent + ? `${descriptorScope}\0${tab}\0${valueEvent.bodyToken}` + : undefined; + + useEffect(() => { + if ((tab !== "inputs" && tab !== "output") || !valueEvent || !valueDetailKey) { + setInputOutputState(undefined); + return; + } + const key = cacheKey("json", valueEvent.bodyToken); + const cached = detailCache.current.get(key); + if (cached) { + detailCache.current.delete(key); + detailCache.current.set(key, cached); + setInputOutputState({ key: valueDetailKey, status: "ready" }); + return; + } + + const generation = detailGeneration.current; + const controller = new AbortController(); + detailControllers.current.add(controller); + setInputOutputState({ key: valueDetailKey, status: "loading" }); + void api + .readJsonDetail(valueEvent.bodyToken, controller.signal) + .then((body) => { + if ( + controller.signal.aborted || + detailGeneration.current !== generation || + tabRef.current !== tab + ) return; + if (!storeCachedDetail(key, body, valueEvent.sizeBytes)) { + setInputOutputState({ + key: valueDetailKey, + status: "error", + error: "Retained value exceeds the browser detail limit.", + }); + return; + } + setInputOutputState({ key: valueDetailKey, status: "ready" }); + }) + .catch((error: unknown) => { + if (controller.signal.aborted || detailGeneration.current !== generation) return; + setInputOutputState({ + key: valueDetailKey, + status: "error", + error: error instanceof Error ? error.message : "Detail unavailable", + }); + }) + .finally(() => detailControllers.current.delete(controller)); + return () => { + controller.abort(); + detailControllers.current.delete(controller); + }; + }, [api, cacheVersion, descriptorScope, tab, valueDetailKey, valueEvent]); + + function hydrateTraceTurn(event: AgentEventDescriptorMsg) { + if (tabRef.current !== "trace") return; + const key = cacheKey("json", event.bodyToken); + if (detailCache.current.has(key) || detailLoading.current.has(key)) return; + const generation = detailGeneration.current; + const controller = new AbortController(); + detailControllers.current.add(controller); + detailLoading.current.add(key); + setDetailErrors((current) => { + if (!(key in current)) return current; + const next = { ...current }; + delete next[key]; + return next; + }); + setDetailLoadingVersion((current) => current + 1); + void api + .readJsonDetail(event.bodyToken, controller.signal) + .then((body) => { + if ( + controller.signal.aborted || + detailGeneration.current !== generation || + tabRef.current !== "trace" + ) return; + if (!storeCachedDetail(key, body, event.sizeBytes)) { + setDetailErrors((current) => ({ + ...current, + [key]: "Turn detail exceeds the browser detail limit.", + })); + } + }) + .catch((error: unknown) => { + if (controller.signal.aborted || detailGeneration.current !== generation) return; + setDetailErrors((current) => ({ + ...current, + [key]: error instanceof Error ? error.message : "Turn detail unavailable", + })); + }) + .finally(() => { + detailControllers.current.delete(controller); + detailLoading.current.delete(key); + if (controller.signal.aborted || detailGeneration.current !== generation) return; + setDetailLoadingVersion((current) => current + 1); + }); + } + + const traceProjection = useMemo(() => { + const descriptors = new WeakMap(); + const values = turns.map((event) => { + const key = cacheKey("json", event.bodyToken); + const cached = detailCache.current.get(key)?.value; + const error = detailErrors[key]; + const loading = detailLoading.current.has(key); + const value = { + ...eventSummary(event), + ...(isUnknownRecord(cached) + ? cached + : cached !== undefined + ? { detail: cached } + : { + detail: error + ? { kind: "unavailable", reason: error } + : loading + ? "Loading retained turn…" + : "Expand this turn to load its retained detail.", + }), + }; + descriptors.set(value, event); + return value; + }); + return { descriptors, values }; + }, [cacheVersion, detailErrors, detailLoadingVersion, turns]); + + const traceRoot = useMemo(() => { + const header = node?.trace?.header; + return { + status: node?.trace?.status, + complete: node?.trace?.complete, + event_count: node?.trace?.eventCount, + size_bytes: node?.trace?.sizeBytes, + model: header?.model, + sub_model: header?.subModel, + iterations: header?.iterations, + max_iterations: header?.maxIterations, + duration_ms: header?.durationMs, + usage: parseRetainedJson(header?.usageJson), + telemetry: parseRetainedJson(header?.telemetryJson), + lifecycle: combinedEvents + .filter((event) => event.eventKind !== "iteration.recorded") + .map(eventSummary), + turns: traceProjection.values, + }; + }, [combinedEvents, node?.trace, traceProjection.values]); + + useEffect(() => { + if (tab !== "trace" || !following || !turns.length || !traceScrollElement.current) return; + traceScrollElement.current.scrollTop = traceScrollElement.current.scrollHeight; + }, [following, tab, turns.length]); + + + if (!run && workflow && nodeId) { + return ( + + ); + } + + if (!run || !node) return null; + const declaredFields = + tab === "inputs" + ? runFieldSchemas?.inputs + : tab === "output" + ? runFieldSchemas?.outputs + : undefined; + const valueCacheEntry = valueEvent + ? detailCache.current.get(cacheKey("json", valueEvent.bodyToken)) + : undefined; + const selectedPayload = eventPayload(valueCacheEntry?.value); + const valueKey = tab === "inputs" ? "inputs" : "outputs"; + const activePageError = pageError?.key === pageKey ? pageError.value : undefined; + const activeInputOutputState = + valueDetailKey !== undefined && inputOutputState?.key === valueDetailKey + ? inputOutputState + : undefined; + const inputOutputLoading = + !activePageError && + (eventPageScope !== pageKey || + (valueDetailKey !== undefined && + valueCacheEntry === undefined && + activeInputOutputState?.status !== "error")); + const inputOutputError = + activeInputOutputState?.status === "error" ? activeInputOutputState.error : undefined; + + return ( + + ); +} diff --git a/web/operator/src/Markdown.tsx b/web/operator/src/Markdown.tsx new file mode 100644 index 0000000..f106378 --- /dev/null +++ b/web/operator/src/Markdown.tsx @@ -0,0 +1,114 @@ +import { memo, useState } from "react"; +import ReactMarkdown from "react-markdown"; + +export const MARKDOWN_SOURCE_CHUNK_CHARACTERS = 4_000; +export const NODE_MARKDOWN_EXCERPT_CHARACTERS = 480; + +const MARKDOWN_ALLOWED_ELEMENTS = [ + "a", + "blockquote", + "br", + "code", + "em", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "hr", + "li", + "ol", + "p", + "pre", + "strong", + "ul", +]; + +interface MarkdownProps { + children: string; + className?: string; + expandable?: boolean; + sourceCharacterBudget?: number; +} + +const MarkdownChunk = memo(({ source }: { source: string }) => ( + + {source} + +)); +MarkdownChunk.displayName = "MarkdownChunk"; + +function MarkdownContent({ + children, + className, + expandable, + sourceCharacterBudget, +}: Required> & + Pick) { + const [visibleChunkCount, setVisibleChunkCount] = useState(1); + const visibleChunks = []; + for ( + let chunkIndex = 0; + chunkIndex < visibleChunkCount && + chunkIndex * sourceCharacterBudget < children.length; + chunkIndex += 1 + ) { + const start = chunkIndex * sourceCharacterBudget; + visibleChunks.push( + , + ); + } + const hasMore = visibleChunkCount * sourceCharacterBudget < children.length; + + return ( +
+ {visibleChunks} + {expandable && hasMore && ( + + )} +
+ ); +} + +function MarkdownSource( + props: Required< + Pick + > & + Pick, +) { + return ; +} + +export function Markdown({ + children, + className, + expandable = true, + sourceCharacterBudget = MARKDOWN_SOURCE_CHUNK_CHARACTERS, +}: MarkdownProps) { + const boundedSourceCharacterBudget = Number.isFinite(sourceCharacterBudget) + ? Math.min( + MARKDOWN_SOURCE_CHUNK_CHARACTERS, + Math.max(1, Math.floor(sourceCharacterBudget)), + ) + : MARKDOWN_SOURCE_CHUNK_CHARACTERS; + return ( + + {children} + + ); +} diff --git a/web/operator/src/RunControls.test.tsx b/web/operator/src/RunControls.test.tsx new file mode 100644 index 0000000..89163b9 --- /dev/null +++ b/web/operator/src/RunControls.test.tsx @@ -0,0 +1,99 @@ +import { fireEvent, render, screen, waitFor } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import type { FlowInfoMsg, RunSnapshotMsg } from "./generated/operator"; +import { parseRunInput, RunControls } from "./RunControls"; + +const workflow = { + workflowId: "flows.py::orders", + displayName: "Orders", +} as FlowInfoMsg; +const running = { + summary: { runId: "run-1", status: "running" }, +} as RunSnapshotMsg; + +describe("RunControls", () => { + it("starts without implicit input and cancels the authoritative active run", async () => { + const onStart = vi.fn(async () => "run-2"); + const onCancel = vi.fn(async () => undefined); + render( + , + ); + + fireEvent.click(screen.getByRole("button", { name: "Run" })); + await waitFor(() => + expect(onStart).toHaveBeenCalledWith("flows.py::orders", undefined), + ); + + fireEvent.click(screen.getByRole("button", { name: "Cancel run" })); + await waitFor(() => expect(onCancel).toHaveBeenCalledWith("run-1")); + }); + + it("keeps Run available while requests are pending", async () => { + const onStart = vi.fn(async () => "run-2"); + render( + undefined} + />, + ); + + const runButton = screen.getByRole("button", { name: "Run" }); + expect(runButton).toBeEnabled(); + fireEvent.click(runButton); + fireEvent.click(runButton); + await waitFor(() => expect(onStart).toHaveBeenCalledTimes(2)); + }); + + it("renders a return control for a historical run", () => { + const onViewWorkflow = vi.fn(); + render( + "run-2"} + onCancel={async () => undefined} + onViewWorkflow={onViewWorkflow} + />, + ); + + fireEvent.click(screen.getByRole("button", { name: "Current workflow" })); + expect(onViewWorkflow).toHaveBeenCalledOnce(); + expect(screen.queryByRole("button", { name: "Run" })).not.toBeInTheDocument(); + }); + + it("keeps the JSON editor closed by default and surfaces operator validation", async () => { + const onStart = vi.fn(async () => { + throw new Error("input.value is required"); + }); + render( + undefined} + />, + ); + + expect(screen.queryByText("Schema-blind JSON object")).not.toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Run" })); + + expect(await screen.findByText("input.value is required")).toBeInTheDocument(); + expect(screen.queryByText("Schema-blind JSON object")).not.toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Add JSON input" })); + expect(screen.getByText("Schema-blind JSON object")).toBeInTheDocument(); + expect( + screen.getByRole("textbox", { name: "Workflow input JSON" }), + ).toBeInTheDocument(); + }); + + it("accepts an explicit JSON object and rejects non-object run input", () => { + expect(parseRunInput('{"value":7}')).toEqual({ value: 7 }); + expect(() => parseRunInput("[1,2,3]")).toThrow("Run input must be a JSON object"); + }); +}); diff --git a/web/operator/src/RunControls.tsx b/web/operator/src/RunControls.tsx new file mode 100644 index 0000000..6dfbe12 --- /dev/null +++ b/web/operator/src/RunControls.tsx @@ -0,0 +1,160 @@ +import { json } from "@codemirror/lang-json"; +import { EditorState } from "@codemirror/state"; +import { EditorView, keymap } from "@codemirror/view"; +import { useEffect, useRef, useState } from "react"; + +import type { FlowInfoMsg, RunSnapshotMsg } from "./generated/operator"; +import { isUnknownRecord } from "./guards"; + +interface JsonEditorProps { + value: string; + onChange: (value: string) => void; +} + +function JsonEditor({ value, onChange }: JsonEditorProps) { + const parent = useRef(null); + useEffect(() => { + if (!parent.current) return; + const view = new EditorView({ + parent: parent.current, + state: EditorState.create({ + doc: value, + extensions: [ + json(), + keymap.of([]), + EditorView.lineWrapping, + EditorView.contentAttributes.of({ + "aria-label": "Workflow input JSON", + }), + EditorView.theme({ + "&": { backgroundColor: "#ffffff", color: "#17211c" }, + ".cm-content": { caretColor: "#2563eb", minHeight: "110px" }, + ".cm-gutters": { backgroundColor: "#f6f8f7", color: "#7b8680", border: "0" }, + "&.cm-focused": { outline: "1px solid #9bb6f5" }, + }), + EditorView.updateListener.of((update) => { + if (update.docChanged) onChange(update.state.doc.toString()); + }), + ], + }), + }); + return () => view.destroy(); + }, []); + return
; +} + +interface RunControlsProps { + workflow?: FlowInfoMsg; + run?: RunSnapshotMsg; + pending?: { kind: "start" | "cancel"; target: string }; + onStart: (workflowSelector: string, input?: Record) => Promise; + onCancel: (runId: string) => Promise; + onViewWorkflow?: () => void; +} + +export function parseRunInput(draft: string): Record { + const parsed: unknown = JSON.parse(draft); + if (!isUnknownRecord(parsed)) throw new Error("Run input must be a JSON object"); + return parsed; +} + + +export function RunControls({ + workflow, + run, + pending, + onStart, + onCancel, + onViewWorkflow, +}: RunControlsProps) { + const [showInput, setShowInput] = useState(false); + const [draft, setDraft] = useState("{}"); + const [error, setError] = useState(); + const active = + run?.summary?.status === "requesting" || + run?.summary?.status === "pending" || + run?.summary?.status === "running"; + + const start = async () => { + if (!workflow) return; + setError(undefined); + let input: Record | undefined; + if (showInput) { + try { + input = parseRunInput(draft); + } catch (reason) { + setError(reason instanceof Error ? reason.message : "Run input is invalid JSON"); + return; + } + } + try { + await onStart(workflow.workflowId, input); + } catch (reason) { + setError(reason instanceof Error ? reason.message : "Operator rejected the run"); + } + }; + + return ( +
+ {onViewWorkflow && ( + + )} + {workflow && ( + <> + + + + )} + {active && run?.summary && ( + + )} + {showInput && workflow && ( +
+
+ Workflow input + Schema-blind JSON object +
+ +
+ )} + {error &&
{error}
} +
+ ); +} diff --git a/web/operator/src/RunListPanel.test.tsx b/web/operator/src/RunListPanel.test.tsx new file mode 100644 index 0000000..b69bf2e --- /dev/null +++ b/web/operator/src/RunListPanel.test.tsx @@ -0,0 +1,126 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +vi.mock("@tanstack/react-virtual", () => ({ + useVirtualizer: ({ count }: { count: number }) => ({ + getTotalSize: () => count * 32, + getVirtualItems: () => + Array.from({ length: count }, (_, index) => ({ + index, + size: 32, + start: index * 32, + })), + }), +})); + +import { RunSummaryMsg } from "./generated/operator"; +import { RunListPanel } from "./RunListPanel"; + +function run( + runId: string, + workflowId: string, + createdSequence: string, + status: string, + startedAt: number, + endedAt: number, + triggeredAt: number, +) { + return RunSummaryMsg.create({ + runId, + workflowId, + workflowDisplayName: workflowId, + createdSequence, + status, + startedAt, + endedAt, + triggeredAt, + }); +} +const RUN_TIMESTAMP_FORMAT = new Intl.DateTimeFormat(undefined, { + dateStyle: "short", + timeStyle: "short", +}); + +describe("RunListPanel", () => { + it("shows compact newest-first rows with status and duration", () => { + render( + , + ); + + const rows = screen.getAllByRole("button"); + expect(rows).toHaveLength(2); + expect(rows[0]).toHaveAccessibleName( + `run-newer, failed, 1.0s, ${RUN_TIMESTAMP_FORMAT.format(new Date(1_704_153_600_000))}`, + ); + expect(rows[1]).toHaveAccessibleName( + `run-older, success, 2.3s, ${RUN_TIMESTAMP_FORMAT.format(new Date(1_704_067_200_000))}`, + ); + expect(rows[1]).toHaveClass("active"); + expect(screen.getByText("2")).toBeInTheDocument(); + expect(screen.getByText(RUN_TIMESTAMP_FORMAT.format(new Date(1_704_153_600_000)))).toHaveAttribute( + "dateTime", + "2024-01-02T00:00:00.000Z", + ); + }); + + it("renders requesting runs in amber", () => { + render( + , + ); + + const row = screen.getByRole("button", { name: /run-requested, requesting/ }); + expect(row.querySelector("[aria-hidden=true]")).toHaveClass("bg-amber"); + expect(screen.getByText("requesting")).toHaveClass("text-amber"); + }); + + it("selects a run and represents incomplete duration explicitly", () => { + const onSelectRun = vi.fn(); + render( + , + ); + + const row = screen.getByRole("button", { + name: "run-active, running, —, trigger time not recorded", + }); + expect(screen.getByText("Trigger time not recorded")).toBeInTheDocument(); + fireEvent.click(row); + expect(onSelectRun).toHaveBeenCalledWith("run-active"); + }); +}); diff --git a/web/operator/src/RunListPanel.tsx b/web/operator/src/RunListPanel.tsx new file mode 100644 index 0000000..79e3cee --- /dev/null +++ b/web/operator/src/RunListPanel.tsx @@ -0,0 +1,112 @@ +import { useVirtualizer } from "@tanstack/react-virtual"; +import { useMemo, useRef } from "react"; + +import type { RunSummaryMsg } from "./generated/operator"; + +const RUN_ROW_HEIGHT = 32; +const RUN_ROW_OVERSCAN = 8; +const RUN_TIMESTAMP_FORMAT = new Intl.DateTimeFormat(undefined, { + dateStyle: "short", + timeStyle: "short", +}); + +interface RunListPanelProps { + workflowId: string; + runs: Record; + selectedRunId?: string; + onSelectRun: (runId: string) => void; +} + +function compareNewestRun(left: RunSummaryMsg, right: RunSummaryMsg) { + const leftSequence = BigInt(left.createdSequence); + const rightSequence = BigInt(right.createdSequence); + if (leftSequence === rightSequence) return left.runId.localeCompare(right.runId); + return leftSequence < rightSequence ? 1 : -1; +} + +function runDuration(summary: RunSummaryMsg) { + if (!summary.startedAt || !summary.endedAt) return "—"; + return `${Math.max(0, summary.endedAt - summary.startedAt).toFixed(1)}s`; +} + +function runTriggeredAt(summary: RunSummaryMsg): Date | undefined { + return summary.triggeredAt ? new Date(summary.triggeredAt * 1000) : undefined; +} + +export function RunListPanel({ + workflowId, + runs, + selectedRunId, + onSelectRun, +}: RunListPanelProps) { + const scrollElement = useRef(null); + const workflowRuns = useMemo( + () => + Object.values(runs) + .filter((summary) => summary.workflowId === workflowId) + .sort(compareNewestRun), + [runs, workflowId], + ); + const virtualizer = useVirtualizer({ + count: workflowRuns.length, + getScrollElement: () => scrollElement.current, + estimateSize: () => RUN_ROW_HEIGHT, + getItemKey: (index) => workflowRuns[index].runId, + overscan: RUN_ROW_OVERSCAN, + }); + + return ( +
+
+ Runs + {workflowRuns.length} +
+ {workflowRuns.length ? ( +
+
+ {virtualizer.getVirtualItems().map((virtualRow) => { + const summary = workflowRuns[virtualRow.index]; + const triggeredAt = runTriggeredAt(summary); + return ( + + ); + })} +
+
+ ) : ( + No runs yet + )} +
+ ); +} diff --git a/web/operator/src/RunLogPane.test.tsx b/web/operator/src/RunLogPane.test.tsx new file mode 100644 index 0000000..39f7a45 --- /dev/null +++ b/web/operator/src/RunLogPane.test.tsx @@ -0,0 +1,356 @@ +import { act, fireEvent, render, screen, waitFor, within } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +vi.mock("@tanstack/react-virtual", () => ({ + useVirtualizer: ({ count }: { count: number }) => ({ + getTotalSize: () => count * 48, + getVirtualItems: () => + Array.from({ length: count }, (_, index) => ({ + index, + size: 48, + start: index * 48, + })), + measureElement: () => undefined, + }), +})); + +import type { LogDescriptorPage, OperatorApi } from "./api"; +import { DETAIL_CACHE_MAX_BYTES } from "./detailProjection"; +import { + CatalogSnapshotMsg, + DescriptorPageOrder, + LogRecordDescriptorMsg, + RunSnapshotMsg, +} from "./generated/operator"; +import { RunLogPane } from "./RunLogPane"; + +const run = RunSnapshotMsg.create({ + operatorInstanceId: "operator-1", + asOfSequence: "9", + summary: { + runId: "run-1", + workflowId: "flow.py::demo", + workflowDisplayName: "demo", + status: "success", + }, + nodes: [ + { nodeId: "fetch_1", name: "fetch", nodeType: "source", status: "success" }, + { nodeId: "validate_1", name: "validate", nodeType: "step", status: "success" }, + ], + logPageToken: "logs", + topology: { + nodeIds: ["fetch_1", "validate_1"], + graph: { fetch_1: { children: ["validate_1"] }, validate_1: { children: [] } }, + nodeTypes: { fetch_1: "source", validate_1: "step" }, + displayNames: { fetch_1: "Fetch", validate_1: "Validate" }, + }, +}); + +function log(sequence: number, nodeId: string, bodyToken = `log-${sequence}`) { + return LogRecordDescriptorMsg.create({ + sequence: String(sequence), + timestamp: 1_700_000_000 + sequence, + level: "INFO", + nodeId, + sizeBytes: "16", + bodyToken, + }); +} + +function page( + records: LogRecordDescriptorMsg[], + nextPageToken = "", + nextCursor = records[0]?.sequence ?? "0", +): LogDescriptorPage { + return { + operatorInstanceId: run.operatorInstanceId, + asOfSequence: run.asOfSequence, + records, + nextPageToken, + nextCursor, + }; +} + +function operatorApi(overrides: Partial = {}): OperatorApi { + const defaults: OperatorApi = { + getCatalog: async () => CatalogSnapshotMsg.create(), + loadBaseline: async () => ({ catalog: CatalogSnapshotMsg.create(), asOfSequence: "0", runs: [] }), + getLatestRunSnapshot: async () => run, + streamUpdates: async function* () { + return; + }, + listLogPage: async () => page([]), + listAgentEventPage: async () => ({ + operatorInstanceId: run.operatorInstanceId, + asOfSequence: run.asOfSequence, + runId: "run-1", + nodeId: "fetch_1", + records: [], + nextPageToken: "", + nextCursor: "0", + }), + readJsonDetail: async () => undefined, + readTextDetail: async (token) => `body-${token}`, + startRun: async () => "run-1", + cancelRun: async () => undefined, + }; + return { ...defaults, ...overrides }; +} + +function deferred() { + let resolve!: (value: T) => void; + const promise = new Promise((done) => { + resolve = done; + }); + return { promise, resolve }; +} + +describe("RunLogPane", () => { + it("merges retained and live records into one ordered cross-step stream", async () => { + const listLogPage = vi.fn(async () => + page([log(2, "validate_1"), log(1, "fetch_1")]), + ); + const readTextDetail = vi.fn(async (token: string) => `body-${token}`); + const onSelectNode = vi.fn(); + render( + , + ); + + const pane = screen.getByRole("region", { name: "Run logs" }); + await waitFor(() => expect(within(pane).getAllByRole("article")).toHaveLength(3)); + await waitFor(() => expect(pane).toHaveTextContent("body-live-2")); + const rows = within(pane).getAllByRole("article"); + expect(rows.map((row) => row.querySelector("pre")?.textContent)).toEqual([ + "body-log-1", + "body-live-2", + "body-log-3", + ]); + expect(listLogPage).toHaveBeenCalledWith( + expect.objectContaining({ + pageToken: "logs", + nodeId: "", + order: DescriptorPageOrder.NEWEST_FIRST, + }), + expect.any(AbortSignal), + ); + + fireEvent.click(within(rows[0]).getByRole("button", { name: /Fetch/ })); + expect(onSelectNode).toHaveBeenCalledWith("fetch_1"); + expect(within(pane).queryByText("Start of retained logs")).not.toBeInTheDocument(); + }); + + it("renders ANSI styles in hydrated log bodies", async () => { + render( + page([log(1, "fetch")]), + readTextDetail: async () => "\u001B[1;31mfailed\u001B[0m", + })} + run={run} + onSelectNode={() => undefined} + />, + ); + + const pane = screen.getByRole("region", { name: "Run logs" }); + const body = await within(pane).findByText("failed"); + expect(body).toHaveStyle({ color: "rgb(196, 61, 54)", fontWeight: "700" }); + expect(within(pane).getByRole("button", { name: /Fetch/ })).toBeInTheDocument(); + }); + + it("uses the canonical graph node ID for the log filter and cancels obsolete scope work", async () => { + const requestSignals: AbortSignal[] = []; + const listLogPage = vi.fn(async (request, signal) => { + if (signal) requestSignals.push(signal); + return request.nodeId === "fetch_1" + ? page([log(1, "fetch_1")]) + : page([log(1, "fetch_1"), log(2, "validate_1")]); + }); + const api = operatorApi({ listLogPage }); + const view = render( + undefined} + />, + ); + + expect(await screen.findByText("Fetch · fetch_1")).toBeInTheDocument(); + await waitFor(() => expect(screen.getAllByRole("article")).toHaveLength(2)); + expect(listLogPage).toHaveBeenLastCalledWith( + expect.objectContaining({ nodeId: "fetch_1" }), + expect.any(AbortSignal), + ); + + view.rerender( + undefined} + />, + ); + await waitFor(() => expect(listLogPage).toHaveBeenCalledTimes(2)); + expect(requestSignals[0].aborted).toBe(true); + expect(await screen.findByText("All steps")).toBeInTheDocument(); + await waitFor(() => expect(screen.getAllByRole("article")).toHaveLength(4)); + }); + + it("preserves older-page position and explicitly controls auto-scroll to new output", async () => { + const olderPage = deferred(); + const listLogPage = vi.fn(async (request) => { + if (request.pageToken === "older") return olderPage.promise; + return page([log(3, "fetch")], "older", "3"); + }); + const api = operatorApi({ listLogPage }); + const view = render( + undefined} />, + ); + + const loadOlder = await screen.findByRole("button", { name: "Load older logs" }); + await screen.findByText("body-log-3"); + const autoScroll = screen.getByRole("button", { name: "Auto-scroll logs" }); + expect(autoScroll).toHaveAttribute("aria-pressed", "true"); + expect(autoScroll).toHaveTextContent("Auto-scroll on"); + const scroll = view.container.querySelector(".run-log-scroll"); + expect(scroll).not.toBeNull(); + let scrollHeight = 1_000; + Object.defineProperties(scroll!, { + scrollHeight: { configurable: true, get: () => scrollHeight }, + clientHeight: { configurable: true, value: 200 }, + scrollTop: { configurable: true, writable: true, value: 500 }, + }); + fireEvent.scroll(scroll!); + expect(autoScroll).toHaveAttribute("aria-pressed", "false"); + expect(autoScroll).toHaveTextContent("Auto-scroll off"); + + fireEvent.click(loadOlder); + expect(listLogPage).toHaveBeenLastCalledWith( + expect.objectContaining({ + pageToken: "older", + beforeSequence: "3", + nodeId: "", + order: DescriptorPageOrder.NEWEST_FIRST, + }), + expect.any(AbortSignal), + ); + scrollHeight = 1_200; + await act(async () => { + olderPage.resolve(page([log(1, "fetch"), log(2, "validate")])); + await olderPage.promise; + }); + await waitFor(() => expect(screen.getAllByRole("article")).toHaveLength(3)); + expect(scroll!.scrollTop).toBe(700); + + view.rerender( + undefined} />, + ); + await waitFor(() => expect(screen.getAllByRole("article")).toHaveLength(4)); + expect(scroll!.scrollTop).toBe(700); + fireEvent.click(autoScroll); + expect(autoScroll).toHaveAttribute("aria-pressed", "true"); + expect(autoScroll).toHaveTextContent("Auto-scroll on"); + expect(scroll!.scrollTop).toBe(1_200); + + scrollHeight = 1_400; + view.rerender( + undefined} + />, + ); + await waitFor(() => expect(screen.getAllByRole("article")).toHaveLength(5)); + expect(scroll!.scrollTop).toBe(1_400); + fireEvent.click(autoScroll); + expect(autoScroll).toHaveAttribute("aria-pressed", "false"); + }); + + it("resizes vertically from an accessible horizontal drag divider", () => { + const view = render( + undefined} />, + ); + const pane = screen.getByRole("region", { name: "Run logs" }); + Object.defineProperty(pane.parentElement, "clientHeight", { + configurable: true, + value: 800, + }); + const divider = screen.getByRole("separator", { name: "Resize logs" }); + expect(divider).toHaveAttribute("aria-orientation", "horizontal"); + expect(divider).toHaveAttribute("aria-valuenow", "260"); + + fireEvent.pointerDown(divider, { pointerId: 1, clientY: 400 }); + fireEvent.pointerMove(divider, { pointerId: 1, clientY: 320 }); + expect(divider).toHaveAttribute("aria-valuenow", "340"); + expect(pane).toHaveStyle({ flexBasis: "340px" }); + + fireEvent.pointerMove(divider, { pointerId: 1, clientY: 700 }); + fireEvent.pointerUp(divider, { pointerId: 1, clientY: 700 }); + expect(divider).toHaveAttribute("aria-valuenow", "140"); + fireEvent.keyDown(divider, { key: "ArrowUp" }); + expect(divider).toHaveAttribute("aria-valuenow", "156"); + fireEvent.keyDown(divider, { key: "End" }); + expect(divider).toHaveAttribute("aria-valuenow", "600"); + + fireEvent.click(screen.getByRole("button", { name: /logsall steps/i })); + expect(screen.queryByRole("separator", { name: "Resize logs" })).not.toBeInTheDocument(); + }); + + it("bounds text decoding and reports an oversized record", async () => { + const oversized = { + ...log(1, "fetch"), + sizeBytes: String(DETAIL_CACHE_MAX_BYTES + 1), + }; + render( + page([oversized]), + readTextDetail: async () => "small body with an oversized declared cost", + })} + run={run} + onSelectNode={() => undefined} + />, + ); + + expect(await screen.findByRole("alert")).toHaveTextContent( + "A log record exceeds the browser detail limit.", + ); + expect(screen.getByText("[log body omitted]")).toBeInTheDocument(); + }); + + it("aborts an active decode batch when the pane collapses", async () => { + const pendingBody = deferred(); + const decodeSignals: AbortSignal[] = []; + const readTextDetail = vi.fn((_token: string, signal?: AbortSignal) => { + if (signal) decodeSignals.push(signal); + return pendingBody.promise; + }); + render( + page(Array.from({ length: 25 }, (_, index) => log(index + 1, "fetch"))), + readTextDetail, + })} + run={run} + onSelectNode={() => undefined} + />, + ); + + await waitFor(() => expect(readTextDetail).toHaveBeenCalledTimes(20)); + fireEvent.click(screen.getByRole("button", { name: /logsall steps/i })); + expect(screen.getByRole("button", { name: /logsall steps/i })).toHaveAttribute( + "aria-expanded", + "false", + ); + expect(decodeSignals).toHaveLength(20); + expect(decodeSignals.every((signal) => signal.aborted)).toBe(true); + expect(screen.queryByRole("status", { name: /Decoding/ })).not.toBeInTheDocument(); + }); +}); diff --git a/web/operator/src/RunLogPane.tsx b/web/operator/src/RunLogPane.tsx new file mode 100644 index 0000000..7fc8712 --- /dev/null +++ b/web/operator/src/RunLogPane.tsx @@ -0,0 +1,613 @@ +import { useVirtualizer } from "@tanstack/react-virtual"; +import { + type CSSProperties, + type KeyboardEvent, + type PointerEvent, + useCallback, + useEffect, + useLayoutEffect, + useMemo, + useRef, + useState, +} from "react"; + +import { AnsiText } from "./AnsiText"; +import type { OperatorApi } from "./api"; +import { + boundDescriptors, + compareSequence, + DESCRIPTOR_PAGE_SIZE, + DETAIL_CACHE_MAX_BYTES, + type DescriptorPageState, + measuredByteCost, + mergeDescriptorPage, + SCROLL_LOAD_THRESHOLD_PX, +} from "./detailProjection"; +import { + DescriptorPageOrder, + type LogRecordDescriptorMsg, + type RunSnapshotMsg, +} from "./generated/operator"; + +const LOG_DECODE_BATCH_SIZE = 20; +const LOG_ROW_ESTIMATE_PX = 48; +const LOG_ROW_OVERSCAN = 12; +const LOG_PANE_MIN_HEIGHT_PX = 140; +const LOG_PANE_DEFAULT_HEIGHT_PX = 260; +const LOG_PANE_DEFAULT_MAX_HEIGHT_PX = 720; +const LOG_PANE_KEYBOARD_STEP_PX = 16; +const EMPTY_LOGS: LogRecordDescriptorMsg[] = []; +const EMPTY_LOG_PAGE: DescriptorPageState = { + records: EMPTY_LOGS, + nextPageToken: "", + nextCursor: "0", +}; + +interface RunLogPaneProps { + api: OperatorApi; + run: RunSnapshotMsg; + nodeId?: string; + liveLogs?: LogRecordDescriptorMsg[]; + onSelectNode: (nodeId: string) => void; +} + +interface ScrollAnchor { + height: number; + top: number; +} + +interface ResizeStart { + clientY: number; + height: number; +} + +function maximumPaneHeight(element: HTMLElement | null) { + const parentHeight = element?.parentElement?.clientHeight ?? 0; + const availableHeight = parentHeight > 0 ? parentHeight : window.innerHeight; + return Math.max(LOG_PANE_MIN_HEIGHT_PX, Math.floor(availableHeight * 0.75)); +} + +function boundedPaneHeight(height: number, maximum: number) { + return Math.min(maximum, Math.max(LOG_PANE_MIN_HEIGHT_PX, height)); +} + +function logTimestamp(timestamp: number) { + if (!Number.isFinite(timestamp)) return "--:--:--.---"; + return new Date(timestamp * 1000).toISOString().slice(11, 23); +} + +export function RunLogPane({ + api, + run, + nodeId, + liveLogs = EMPTY_LOGS, + onSelectNode, +}: RunLogPaneProps) { + const [expanded, setExpanded] = useState(true); + const [following, setFollowing] = useState(true); + const [paneHeight, setPaneHeight] = useState(LOG_PANE_DEFAULT_HEIGHT_PX); + const [maximumHeight, setMaximumHeight] = useState(LOG_PANE_DEFAULT_MAX_HEIGHT_PX); + const [page, setPage] = useState>(EMPTY_LOG_PAGE); + const [pageScope, setPageScope] = useState(); + const [pageLoading, setPageLoading] = useState(false); + const [pageError, setPageError] = useState(); + const [logBodies, setLogBodies] = useState>(() => new Map()); + const [decodePending, setDecodePending] = useState(false); + const [decodeError, setDecodeError] = useState(); + const [decodeVersion, setDecodeVersion] = useState(0); + + const pageController = useRef(null); + const pageGeneration = useRef(0); + const pageRequestInFlight = useRef(false); + const decodeController = useRef(null); + const decodeGeneration = useRef(0); + const decodeActive = useRef(false); + const loadingTokens = useRef(new Set()); + const droppedTokens = useRef(new Set()); + const combinedLogsRef = useRef([]); + const scrollElement = useRef(null); + const pendingScrollAnchor = useRef(undefined); + const paneElement = useRef(null); + const resizeStart = useRef(undefined); + + const runId = run.summary?.runId ?? ""; + const operatorInstanceId = run.operatorInstanceId; + const asOfSequence = run.asOfSequence; + const pageToken = run.logPageToken; + const exactLogNodeId = nodeId ?? ""; + const descriptorScope = `${operatorInstanceId}\0${runId}\0${asOfSequence}\0${pageToken}\0${exactLogNodeId}`; + const activePage = pageScope === descriptorScope ? page : EMPTY_LOG_PAGE; + + const abortDecoding = useCallback(() => { + decodeGeneration.current += 1; + decodeController.current?.abort(); + decodeController.current = null; + decodeActive.current = false; + loadingTokens.current.clear(); + }, []); + + useEffect( + () => () => { + pageController.current?.abort(); + abortDecoding(); + }, + [abortDecoding], + ); + + useLayoutEffect(() => { + const updateBounds = () => { + const maximum = maximumPaneHeight(paneElement.current); + setMaximumHeight(maximum); + setPaneHeight((current) => boundedPaneHeight(current, maximum)); + }; + updateBounds(); + window.addEventListener("resize", updateBounds); + return () => window.removeEventListener("resize", updateBounds); + }, []); + + useEffect(() => { + pageController.current?.abort(); + pageRequestInFlight.current = false; + abortDecoding(); + const generation = ++pageGeneration.current; + setPage(EMPTY_LOG_PAGE); + setPageScope(undefined); + setPageLoading(false); + setPageError(undefined); + setLogBodies(new Map()); + setDecodePending(false); + setDecodeError(undefined); + droppedTokens.current.clear(); + pendingScrollAnchor.current = undefined; + setFollowing(true); + if (!expanded) return; + + const controller = new AbortController(); + pageController.current = controller; + if (!pageToken) { + setPageScope(descriptorScope); + return () => controller.abort(); + } + + pageRequestInFlight.current = true; + setPageLoading(true); + void api + .listLogPage( + { + pageToken, + afterSequence: "0", + beforeSequence: "0", + pageSize: DESCRIPTOR_PAGE_SIZE, + nodeId: exactLogNodeId, + order: DescriptorPageOrder.NEWEST_FIRST, + expectedOperatorInstanceId: operatorInstanceId, + expectedAsOfSequence: asOfSequence, + }, + controller.signal, + ) + .then((next) => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + setPage(next); + setPageScope(descriptorScope); + }) + .catch((error: unknown) => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + setPageError(error instanceof Error ? error.message : "Logs unavailable"); + }) + .finally(() => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + pageRequestInFlight.current = false; + setPageLoading(false); + }); + return () => { + controller.abort(); + if (pageController.current === controller) pageRequestInFlight.current = false; + }; + }, [ + abortDecoding, + api, + asOfSequence, + descriptorScope, + exactLogNodeId, + expanded, + operatorInstanceId, + pageToken, + ]); + + const combinedLogs = useMemo(() => { + const recordsBySequence = new Map(); + const liveSequences = new Set(); + for (const entry of activePage.records) { + if (!exactLogNodeId || entry.nodeId === exactLogNodeId) { + recordsBySequence.set(entry.sequence, entry); + } + } + for (const entry of liveLogs) { + if (!exactLogNodeId || entry.nodeId === exactLogNodeId) { + recordsBySequence.set(entry.sequence, entry); + liveSequences.add(entry.sequence); + } + } + return boundDescriptors( + recordsBySequence, + (entry) => entry.sequence, + "older", + liveSequences, + ).sort((left, right) => compareSequence(left.sequence, right.sequence)); + }, [activePage.records, exactLogNodeId, liveLogs]); + combinedLogsRef.current = combinedLogs; + + const loadOlderLogs = useCallback(() => { + if (!activePage.nextPageToken || pageRequestInFlight.current) return; + pageController.current?.abort(); + const generation = ++pageGeneration.current; + const controller = new AbortController(); + pageController.current = controller; + pageRequestInFlight.current = true; + setPageError(undefined); + setPageLoading(true); + setFollowing(false); + const element = scrollElement.current; + pendingScrollAnchor.current = element + ? { height: element.scrollHeight, top: element.scrollTop } + : undefined; + void api + .listLogPage( + { + pageToken: activePage.nextPageToken, + afterSequence: "0", + beforeSequence: activePage.nextCursor, + pageSize: DESCRIPTOR_PAGE_SIZE, + nodeId: exactLogNodeId, + order: DescriptorPageOrder.NEWEST_FIRST, + expectedOperatorInstanceId: operatorInstanceId, + expectedAsOfSequence: asOfSequence, + }, + controller.signal, + ) + .then((next) => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + setPage((current) => + mergeDescriptorPage(current, next, (entry) => entry.sequence, "older"), + ); + }) + .catch((error: unknown) => { + pendingScrollAnchor.current = undefined; + if (controller.signal.aborted || pageGeneration.current !== generation) return; + setPageError(error instanceof Error ? error.message : "Logs unavailable"); + }) + .finally(() => { + if (controller.signal.aborted || pageGeneration.current !== generation) return; + pageRequestInFlight.current = false; + setPageLoading(false); + }); + }, [ + activePage.nextCursor, + activePage.nextPageToken, + api, + asOfSequence, + exactLogNodeId, + operatorInstanceId, + ]); + + useLayoutEffect(() => { + const anchor = pendingScrollAnchor.current; + const element = scrollElement.current; + if (!anchor || !element) return; + element.scrollTop = anchor.top + element.scrollHeight - anchor.height; + pendingScrollAnchor.current = undefined; + }, [combinedLogs.length]); + + useEffect(() => { + if (!expanded || !combinedLogs.length || decodeActive.current) return; + const missing = combinedLogs + .filter( + (entry) => + !logBodies.has(entry.bodyToken) && + !loadingTokens.current.has(entry.bodyToken) && + !droppedTokens.current.has(entry.bodyToken), + ) + .slice(0, LOG_DECODE_BATCH_SIZE); + if (!missing.length) return; + + const generation = decodeGeneration.current; + const controller = new AbortController(); + decodeController.current = controller; + decodeActive.current = true; + for (const entry of missing) loadingTokens.current.add(entry.bodyToken); + setDecodePending(true); + const requests = missing.map(async (entry) => { + try { + const body = await api.readTextDetail(entry.bodyToken, controller.signal); + return { entry, body }; + } catch (error: unknown) { + return { entry, error }; + } + }); + void Promise.all(requests) + .then((results) => { + if (controller.signal.aborted || decodeGeneration.current !== generation) return; + const failed = results.find((result) => "error" in result); + if (failed && "error" in failed) { + setDecodeError( + failed.error instanceof Error ? failed.error.message : "Log text unavailable", + ); + } + const oversizedRecord = results.some( + (result) => + "body" in result && + typeof result.body === "string" && + measuredByteCost(result.body, result.entry.sizeBytes) > DETAIL_CACHE_MAX_BYTES, + ); + if (oversizedRecord) setDecodeError("A log record exceeds the browser detail limit."); + setLogBodies((current) => { + const next = new Map(current); + for (const result of results) { + if (!("body" in result) || typeof result.body !== "string") { + droppedTokens.current.add(result.entry.bodyToken); + continue; + } + const byteCost = measuredByteCost(result.body, result.entry.sizeBytes); + if (byteCost > DETAIL_CACHE_MAX_BYTES) { + droppedTokens.current.add(result.entry.bodyToken); + continue; + } + next.set(result.entry.bodyToken, result.body); + } + const retainedDescriptors = new Map( + combinedLogsRef.current.map((entry) => [entry.bodyToken, entry]), + ); + for (const token of next.keys()) { + if (!retainedDescriptors.has(token)) next.delete(token); + } + for (const token of droppedTokens.current) { + if (!retainedDescriptors.has(token)) droppedTokens.current.delete(token); + } + let retainedBytes = 0; + for (const [token, body] of next) { + retainedBytes += measuredByteCost(body, retainedDescriptors.get(token)?.sizeBytes); + } + for (const entry of combinedLogsRef.current) { + if (retainedBytes <= DETAIL_CACHE_MAX_BYTES) break; + const body = next.get(entry.bodyToken); + if (body === undefined) continue; + next.delete(entry.bodyToken); + droppedTokens.current.add(entry.bodyToken); + retainedBytes -= measuredByteCost(body, entry.sizeBytes); + } + return next; + }); + }) + .finally(() => { + for (const entry of missing) loadingTokens.current.delete(entry.bodyToken); + if (decodeController.current !== controller) return; + decodeController.current = null; + decodeActive.current = false; + if (controller.signal.aborted || decodeGeneration.current !== generation) return; + setDecodePending(false); + setDecodeVersion((current) => current + 1); + }); + }, [api, combinedLogs, decodeVersion, expanded, logBodies]); + + useEffect(() => { + const element = scrollElement.current; + if (!expanded || !following || !element) return; + element.scrollTop = element.scrollHeight; + }, [combinedLogs.length, decodeVersion, expanded, following]); + + const enableAutoScroll = useCallback(() => { + const element = scrollElement.current; + if (element) element.scrollTop = element.scrollHeight; + setFollowing(true); + }, []); + + const endResize = (event: PointerEvent) => { + if (!resizeStart.current) return; + if (event.currentTarget.hasPointerCapture?.(event.pointerId)) { + event.currentTarget.releasePointerCapture(event.pointerId); + } + resizeStart.current = undefined; + }; + + const resizeWithKeyboard = (event: KeyboardEvent) => { + const maximum = maximumPaneHeight(paneElement.current); + setMaximumHeight(maximum); + let nextHeight: number | undefined; + if (event.key === "ArrowUp") nextHeight = paneHeight + LOG_PANE_KEYBOARD_STEP_PX; + if (event.key === "ArrowDown") nextHeight = paneHeight - LOG_PANE_KEYBOARD_STEP_PX; + if (event.key === "Home") nextHeight = LOG_PANE_MIN_HEIGHT_PX; + if (event.key === "End") nextHeight = maximum; + if (nextHeight === undefined) return; + event.preventDefault(); + setPaneHeight(boundedPaneHeight(nextHeight, maximum)); + }; + + const virtualizer = useVirtualizer({ + count: combinedLogs.length, + getScrollElement: () => scrollElement.current, + estimateSize: () => LOG_ROW_ESTIMATE_PX, + getItemKey: (index) => combinedLogs[index].sequence, + overscan: LOG_ROW_OVERSCAN, + }); + const nodeDisplayNames = run.topology?.displayNames ?? {}; + const graphNodesByIdentity = useMemo(() => { + const byId = new Map(); + const byUniqueName = new Map(); + for (const candidate of run.nodes) { + byId.set(candidate.nodeId, candidate); + if (byUniqueName.has(candidate.name)) { + byUniqueName.set(candidate.name, undefined); + } else { + byUniqueName.set(candidate.name, candidate); + } + } + return { byId, byUniqueName }; + }, [run.nodes]); + const scopeLabel = nodeId + ? nodeDisplayNames[nodeId] && nodeDisplayNames[nodeId] !== nodeId + ? `${nodeDisplayNames[nodeId]} · ${nodeId}` + : nodeId + : "All steps"; + + const paneStyle = expanded + ? ({ flexBasis: `${paneHeight}px` } satisfies CSSProperties) + : undefined; + + return ( +
+ {expanded && ( +
{ + event.preventDefault(); + const maximum = maximumPaneHeight(paneElement.current); + setMaximumHeight(maximum); + resizeStart.current = { + clientY: event.clientY, + height: boundedPaneHeight(paneHeight, maximum), + }; + event.currentTarget.setPointerCapture?.(event.pointerId); + }} + onPointerMove={(event) => { + const start = resizeStart.current; + if (!start) return; + const maximum = maximumPaneHeight(paneElement.current); + setMaximumHeight(maximum); + setPaneHeight( + boundedPaneHeight(start.height + start.clientY - event.clientY, maximum), + ); + }} + onPointerUp={endResize} + onPointerCancel={endResize} + /> + )} +
+ + + {combinedLogs.length} {combinedLogs.length === 1 ? "record" : "records"} + + {expanded && ( + + )} +
+ {expanded && ( +
+ {pageError &&

{pageError}

} + {decodeError &&

{decodeError}

} + {activePage.nextPageToken && ( + + )} +
{ + const element = event.currentTarget; + const distanceFromBottom = element.scrollHeight - element.scrollTop - element.clientHeight; + if (distanceFromBottom > SCROLL_LOAD_THRESHOLD_PX) setFollowing(false); + if (element.scrollTop <= SCROLL_LOAD_THRESHOLD_PX && activePage.nextPageToken) { + loadOlderLogs(); + } + }} + > + {pageLoading && !combinedLogs.length ? ( +

Loading retained logs…

+ ) : !combinedLogs.length ? ( +

+ {nodeId ? "No retained logs are available for this node." : "No retained logs are available for this run."} +

+ ) : ( +
+ {virtualizer.getVirtualItems().map((virtualRow) => { + const entry = combinedLogs[virtualRow.index]; + const body = logBodies.get(entry.bodyToken); + const graphNode = + graphNodesByIdentity.byId.get(entry.nodeId) ?? + graphNodesByIdentity.byUniqueName.get(entry.nodeId); + const graphNodeId = graphNode?.nodeId; + const nodeLabel = graphNodeId + ? nodeDisplayNames[graphNodeId] || entry.nodeId + : entry.nodeId; + return ( +
+ + {graphNodeId ? ( + + ) : ( + + {nodeLabel} + + )} + {entry.level} +
+
+ ); + })} +
+ )} +
+ {decodePending &&

Decoding log text…

} +
+ )} +
+ ); +} diff --git a/web/operator/src/ValueView.test.tsx b/web/operator/src/ValueView.test.tsx new file mode 100644 index 0000000..bc591e7 --- /dev/null +++ b/web/operator/src/ValueView.test.tsx @@ -0,0 +1,131 @@ +import { fireEvent, render, screen } from "@testing-library/react"; +import { describe, expect, it, vi } from "vitest"; + +import { ValueView } from "./ValueView"; + +describe("ValueView", () => { + it("shows root JSON content directly without generic object summary buttons", () => { + render(); + + expect(screen.getByText("answer")).toBeInTheDocument(); + expect(screen.getByText("readable root")).toBeInTheDocument(); + expect(screen.getByText("count")).toBeInTheDocument(); + expect(screen.getByText("3")).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Object/i })).not.toBeInTheDocument(); + expect(screen.getByRole("tree", { name: "JSON value" })).toBeInTheDocument(); + }); + + it("uses key-named controls and expands nested values independently", () => { + const onExpand = vi.fn(); + render( + , + ); + + expect(screen.getByText("outer value")).toBeInTheDocument(); + expect(screen.queryByText("nested value")).not.toBeInTheDocument(); + const nested = screen.getByRole("button", { name: "Expand nested" }); + const items = screen.getByRole("button", { name: "Expand items" }); + expect(nested).toHaveAttribute("aria-expanded", "false"); + expect(items).toHaveAttribute("aria-expanded", "false"); + expect(screen.queryByRole("button", { name: /Object/i })).not.toBeInTheDocument(); + + fireEvent.click(nested); + + expect(nested).toHaveAttribute("aria-expanded", "true"); + expect(screen.getByText("secret")).toBeInTheDocument(); + expect(screen.getByText("nested value")).toBeInTheDocument(); + expect(screen.queryByText("first item")).not.toBeInTheDocument(); + expect(onExpand).toHaveBeenCalledWith( + expect.objectContaining({ secret: "nested value" }), + ["nested"], + ); + }); + + it("reveals root collection children in deterministic groups of at most 100", () => { + const values = Array.from({ length: 205 }, (_, index) => `item-${index}`); + const { container } = render(); + + expect(screen.getByText("item-0")).toBeInTheDocument(); + expect(screen.getByText("item-99")).toBeInTheDocument(); + expect(screen.queryByText("item-100")).not.toBeInTheDocument(); + expect(container.querySelector(".value-group")?.children).toHaveLength(100); + + fireEvent.click(screen.getByRole("button", { name: "Show 100 more items" })); + expect(screen.getByText("item-100")).toBeInTheDocument(); + expect(screen.getByText("item-199")).toBeInTheDocument(); + expect(screen.queryByText("item-200")).not.toBeInTheDocument(); + + fireEvent.click(screen.getByRole("button", { name: "Show 5 more items" })); + expect(screen.getByText("item-204")).toBeInTheDocument(); + expect(container.querySelector(".value-group")?.children).toHaveLength(205); + }); + + it("bounds object properties before enumerating an additional group", () => { + const value: Record = {}; + for (let index = 0; index < 101; index += 1) value[`key-${index}`] = `value-${index}`; + render(); + + expect(screen.getByText("key-99")).toBeInTheDocument(); + expect(screen.queryByText("key-100")).not.toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Show 1 more property" })); + expect(screen.getByText("key-100")).toBeInTheDocument(); + }); + + it("stops collection disclosure at the maximum depth", () => { + render(); + + expect( + screen.getByRole("note", { + name: "1 property. Deeper values are not shown (maximum depth 12).", + }), + ).toBeInTheDocument(); + expect(screen.queryByText("hidden")).not.toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Expand/ })).not.toBeInTheDocument(); + }); + + it("keeps deep rows in pane-local overflow classes instead of narrow recursive columns", () => { + render(); + + const tree = screen.getByRole("tree", { name: "JSON value" }); + expect(tree).toHaveClass("value-tree"); + expect(screen.getByText("deeply_nested_field_name").closest(".value-row")).toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Expand deeply_nested_field_name" })); + const nextContent = screen.getByRole("button", { name: "Expand next" }).closest(".value-content"); + expect(nextContent).toBeInTheDocument(); + expect(tree.querySelector(".value-child-group")).toBeInTheDocument(); + }); + + it("truncates long strings until explicitly expanded", () => { + const value = "x".repeat(300); + render(); + + expect(screen.getByText(`${"x".repeat(240)}…`)).toBeInTheDocument(); + expect(screen.queryByText(value)).not.toBeInTheDocument(); + fireEvent.click(screen.getByRole("button", { name: "Show full string" })); + expect(screen.getByText(value)).toBeInTheDocument(); + expect(screen.getByRole("button", { name: "Show less" })).toHaveAttribute( + "aria-expanded", + "true", + ); + }); + + it("renders scalar, file, and unavailable values immediately", () => { + const { rerender } = render(); + expect(screen.getByText("null")).toHaveClass("value-null"); + + rerender(); + expect(screen.getByText("PredictRLM file")).toBeInTheDocument(); + expect(screen.getByText("/tmp/report.pdf")).toBeInTheDocument(); + expect(screen.getByTitle(/contents are not copied/i)).toBeInTheDocument(); + + rerender(); + expect(screen.getByText("Unavailable · unsupported socket")).toBeInTheDocument(); + }); +}); diff --git a/web/operator/src/ValueView.tsx b/web/operator/src/ValueView.tsx new file mode 100644 index 0000000..3b8d102 --- /dev/null +++ b/web/operator/src/ValueView.tsx @@ -0,0 +1,239 @@ +import { useId, useState } from "react"; + +import { isUnknownRecord } from "./guards"; + +interface ValueViewProps { + value: unknown; + depth?: number; + onExpand?: (value: unknown, path: ReadonlyArray) => void; +} + +interface CollectionProps { + value: unknown[] | Record; + depth: number; + path: ReadonlyArray; + onExpand?: ValueViewProps["onExpand"]; +} + +const CHILDREN_PER_GROUP = 100; +const STRING_PREVIEW_LENGTH = 240; +const MAX_DISCLOSURE_DEPTH = 12; + +function plural(count: number, singular: string, pluralForm = `${singular}s`) { + return count === 1 ? singular : pluralForm; +} + +function ownEntries(value: Record): Array<[string, unknown]> { + const entries: Array<[string, unknown]> = []; + for (const key in value) { + if (Object.prototype.hasOwnProperty.call(value, key)) entries.push([key, value[key]]); + } + return entries; +} + +function collectionCount(value: unknown[] | Record) { + return Array.isArray(value) ? value.length : ownEntries(value).length; +} + +function collectionSummary(value: unknown[] | Record) { + const count = collectionCount(value); + return Array.isArray(value) + ? `[${count} ${plural(count, "item")}]` + : `{${count} ${plural(count, "property", "properties")}}`; +} + +function LongString({ value }: { value: string }) { + const [expanded, setExpanded] = useState(false); + const contentId = useId(); + + return ( + + + {expanded ? value : `${value.slice(0, STRING_PREVIEW_LENGTH)}…`} + {" "} + + + ); +} + +function TruncatedCollection({ + value, +}: { + value: unknown[] | Record; +}) { + const count = collectionCount(value); + const itemLabel = Array.isArray(value) + ? plural(count, "item") + : plural(count, "property", "properties"); + const summary = `${count} ${itemLabel}. Deeper values are not shown (maximum depth ${MAX_DISCLOSURE_DEPTH}).`; + + return ( + + {collectionSummary(value)} · maximum depth reached + + ); +} + +function ScalarValue({ value }: { value: unknown }) { + if (value === null) return null; + if (typeof value === "string") { + return value.length > STRING_PREVIEW_LENGTH ? ( + + ) : ( + {value} + ); + } + if (typeof value === "number" || typeof value === "boolean") { + return {String(value)}; + } + if (isUnknownRecord(value)) { + if (value.kind === "predict_rlm_file" && typeof value.path === "string") { + return ( + + + + PredictRLM file + {value.path} + + + ); + } + if (value.kind === "unavailable" && typeof value.reason === "string") { + return Unavailable · {value.reason}; + } + } + return Unavailable; +} + + +function isCollection(value: unknown): value is unknown[] | Record { + return ( + Array.isArray(value) || + (isUnknownRecord(value) && + !( + (value.kind === "predict_rlm_file" && typeof value.path === "string") || + (value.kind === "unavailable" && typeof value.reason === "string") + )) + ); +} + +function CollectionNode({ + label, + value, + depth, + path, + onExpand, +}: CollectionProps & { label: string }) { + const [expanded, setExpanded] = useState(false); + const contentId = useId(); + const atDepthLimit = depth >= MAX_DISCLOSURE_DEPTH; + + if (atDepthLimit) return ; + + return ( +
+ + {expanded && ( +
+ +
+ )} +
+ ); +} + +function CollectionChildren({ value, depth, path, onExpand }: CollectionProps) { + const [visibleCount, setVisibleCount] = useState(CHILDREN_PER_GROUP); + const entries: Array<[string | number, unknown]> = Array.isArray(value) + ? value.slice(0, visibleCount).map((item, index) => [index, item]) + : ownEntries(value).slice(0, visibleCount); + const count = collectionCount(value); + const remaining = count - entries.length; + const nextCount = Math.min(CHILDREN_PER_GROUP, remaining); + + if (!count) { + return {Array.isArray(value) ? "[]" : "{}"}; + } + + return ( + <> +
    + {entries.map(([key, item]) => { + const childPath = [...path, key]; + const nested = isCollection(item); + return ( +
  • +
    + {Array.isArray(value) ? `[${key}]` : key} + +
    + {nested ? ( + + ) : ( + + )} +
    +
    +
  • + ); + })} +
+ {remaining > 0 && ( + + )} + + ); +} + +export function ValueView({ value, depth = 0, onExpand }: ValueViewProps) { + if (!isCollection(value)) return ; + if (depth >= MAX_DISCLOSURE_DEPTH) return ; + + return ( +
+ +
+ ); +} diff --git a/web/operator/src/api.test.ts b/web/operator/src/api.test.ts new file mode 100644 index 0000000..2137356 --- /dev/null +++ b/web/operator/src/api.test.ts @@ -0,0 +1,253 @@ +import { describe, expect, it, vi } from "vitest"; + +import { + GrpcWebOperatorApi, + type AgentEventPageRequest, + type LogPageRequest, +} from "./api"; +import type { OperatorServiceClient } from "./generated/operator.client"; +import { + AgentEventDescriptorMsg, + AgentEventPage, + CatalogSnapshotMsg, + DescriptorPageOrder, + DetailChunk, + LogPage, + LogRecordDescriptorMsg, + RunSnapshotMsg, + RunSummaryMsg, + RunSummaryPage, +} from "./generated/operator"; + +function apiWith(client: object): GrpcWebOperatorApi { + return new GrpcWebOperatorApi( + "http://operator.test", + client as unknown as OperatorServiceClient, + ); +} +function detailStream(parts: Uint8Array[]) { + return (async function* () { + for (const data of parts) yield DetailChunk.create({ data }); + })(); +} + +describe("GrpcWebOperatorApi", () => { + it("loads a summary-only baseline without requesting run snapshots", async () => { + const signal = new AbortController().signal; + const catalog = CatalogSnapshotMsg.create({ + operatorInstanceId: "operator-1", + asOfSequence: "8", + revision: "3", + }); + const summary = RunSummaryMsg.create({ runId: "run-1", revision: "2" }); + const getCatalog = vi.fn(() => ({ response: Promise.resolve(catalog) })); + const listRunSummaries = vi.fn(() => ({ + response: Promise.resolve( + RunSummaryPage.create({ + operatorInstanceId: "operator-1", + asOfSequence: "8", + runs: [summary], + }), + ), + })); + const getRunSnapshot = vi.fn(); + const getLatestRunSnapshot = vi.fn(); + const api = apiWith({ + getCatalog, + listRunSummaries, + getRunSnapshot, + getLatestRunSnapshot, + }); + + await expect(api.loadBaseline(signal)).resolves.toEqual({ + catalog, + asOfSequence: "8", + runs: [summary], + }); + expect(listRunSummaries).toHaveBeenCalledOnce(); + expect(listRunSummaries).toHaveBeenCalledWith( + { workflowSelector: "", pageSize: 100, pageToken: "" }, + { abort: signal }, + ); + expect(getCatalog).toHaveBeenCalledTimes(2); + expect(getCatalog).toHaveBeenNthCalledWith(1, {}, { abort: signal }); + expect(getCatalog).toHaveBeenNthCalledWith(2, {}, { abort: signal }); + expect(getRunSnapshot).not.toHaveBeenCalled(); + expect(getLatestRunSnapshot).not.toHaveBeenCalled(); + }); + + it("requests exactly one typed log and event page with filters, order, and cancellation", async () => { + const signal = new AbortController().signal; + const log = LogRecordDescriptorMsg.create({ sequence: "10", nodeId: "agent" }); + const event = AgentEventDescriptorMsg.create({ eventSequence: "3" }); + const listLogs = vi.fn(() => ({ + response: Promise.resolve( + LogPage.create({ + operatorInstanceId: "operator-1", + asOfSequence: "20", + logs: [log], + nextPageToken: "log-next", + }), + ), + })); + const listAgentEvents = vi.fn(() => ({ + response: Promise.resolve( + AgentEventPage.create({ + operatorInstanceId: "operator-1", + asOfSequence: "20", + runId: "run-1", + nodeId: "agent", + events: [event], + nextPageToken: "event-next", + }), + ), + })); + const api = apiWith({ listLogs, listAgentEvents }); + const logRequest: LogPageRequest = { + pageToken: "log-page", + afterSequence: "0", + beforeSequence: "11", + pageSize: 25, + nodeId: "agent", + order: DescriptorPageOrder.NEWEST_FIRST, + expectedOperatorInstanceId: "operator-1", + expectedAsOfSequence: "20", + }; + const eventRequest: AgentEventPageRequest = { + pageToken: "event-page", + afterEventSequence: "2", + beforeEventSequence: "0", + pageSize: 30, + order: DescriptorPageOrder.FORWARD, + expectedOperatorInstanceId: "operator-1", + expectedAsOfSequence: "20", + expectedRunId: "run-1", + expectedNodeId: "agent", + }; + + await expect(api.listLogPage(logRequest, signal)).resolves.toEqual({ + operatorInstanceId: "operator-1", + asOfSequence: "20", + records: [log], + nextPageToken: "log-next", + nextCursor: "10", + }); + await expect(api.listAgentEventPage(eventRequest, signal)).resolves.toEqual({ + operatorInstanceId: "operator-1", + asOfSequence: "20", + runId: "run-1", + nodeId: "agent", + records: [event], + nextPageToken: "event-next", + nextCursor: "3", + }); + expect(listLogs).toHaveBeenCalledOnce(); + expect(listLogs).toHaveBeenCalledWith( + { + pageToken: "log-page", + afterSequence: "0", + beforeSequence: "11", + pageSize: 25, + nodeId: "agent", + order: DescriptorPageOrder.NEWEST_FIRST, + }, + { abort: signal }, + ); + expect(listAgentEvents).toHaveBeenCalledOnce(); + expect(listAgentEvents).toHaveBeenCalledWith( + { + pageToken: "event-page", + afterEventSequence: "2", + beforeEventSequence: "0", + pageSize: 30, + order: DescriptorPageOrder.FORWARD, + }, + { abort: signal }, + ); + }); + + it("rejects a page that cannot advance its continuation", async () => { + const api = apiWith({ + listLogs: vi.fn(() => ({ + response: Promise.resolve( + LogPage.create({ + operatorInstanceId: "operator-1", + asOfSequence: "20", + nextPageToken: "same-page", + }), + ), + })), + }); + + await expect( + api.listLogPage({ + pageToken: "same-page", + afterSequence: "4", + beforeSequence: "0", + pageSize: 25, + nodeId: "", + order: DescriptorPageOrder.FORWARD, + expectedOperatorInstanceId: "operator-1", + expectedAsOfSequence: "20", + }), + ).rejects.toThrow("Log pagination made no progress"); + }); + + it("propagates cancellation to latest snapshots and update streams", async () => { + const signal = new AbortController().signal; + const snapshot = RunSnapshotMsg.create({ operatorInstanceId: "operator-1" }); + const getLatestRunSnapshot = vi.fn(() => ({ response: Promise.resolve(snapshot) })); + const responses = detailStream([]); + const streamOperatorUpdates = vi.fn(() => ({ responses })); + const api = apiWith({ getLatestRunSnapshot, streamOperatorUpdates }); + + await expect( + api.getLatestRunSnapshot("run-1", "operator-1", signal), + ).resolves.toBe(snapshot); + expect(api.streamUpdates("operator-1", "9", signal)).toBe(responses); + expect(getLatestRunSnapshot).toHaveBeenCalledWith( + { runId: "run-1", operatorInstanceId: "operator-1" }, + { abort: signal }, + ); + expect(streamOperatorUpdates).toHaveBeenCalledWith( + { operatorInstanceId: "operator-1", afterSequence: "9" }, + { abort: signal }, + ); + }); + + it("decodes UTF-8 across chunks and never JSON-parses plain log text", async () => { + const signal = new AbortController().signal; + const encoder = new TextEncoder(); + const json = encoder.encode('{"message":"A😀B"}'); + const emojiStart = json.indexOf(0xf0); + const text = encoder.encode("plain log: not JSON }"); + const readDetail = vi.fn(({ bodyToken }: { bodyToken: string }) => ({ + responses: + bodyToken === "json-body" + ? detailStream([ + json.slice(0, emojiStart + 2), + json.slice(emojiStart + 2, emojiStart + 3), + json.slice(emojiStart + 3), + ]) + : detailStream([text.slice(0, 7), text.slice(7)]), + })); + const api = apiWith({ readDetail }); + + await expect(api.readJsonDetail("json-body", signal)).resolves.toEqual({ + message: "A😀B", + }); + await expect(api.readTextDetail("text-body", signal)).resolves.toBe( + "plain log: not JSON }", + ); + expect(readDetail).toHaveBeenNthCalledWith( + 1, + { bodyToken: "json-body" }, + { abort: signal }, + ); + expect(readDetail).toHaveBeenNthCalledWith( + 2, + { bodyToken: "text-body" }, + { abort: signal }, + ); + }); +}); diff --git a/web/operator/src/api.ts b/web/operator/src/api.ts new file mode 100644 index 0000000..59150e7 --- /dev/null +++ b/web/operator/src/api.ts @@ -0,0 +1,331 @@ +import { GrpcWebFetchTransport } from "@protobuf-ts/grpcweb-transport"; + +import { DescriptorPageOrder } from "./generated/operator"; + +import { OperatorServiceClient } from "./generated/operator.client"; +import type { + AgentEventDescriptorMsg, + CatalogSnapshotMsg, + ListAgentEventsRequest, + ListLogsRequest, + LogRecordDescriptorMsg, + OperatorUpdateEnvelope, + RunSnapshotMsg, + RunSummaryMsg, +} from "./generated/operator"; + +const MAX_BASELINE_PAGES = 100; +const MAX_BASELINE_SUMMARIES = 10_000; +const MAX_BASELINE_BYTES = 8 * 1024 * 1024; + +export interface StructuralBaseline { + catalog: CatalogSnapshotMsg; + asOfSequence: string; + runs: RunSummaryMsg[]; +} + +export interface LogPageRequest extends ListLogsRequest { + expectedOperatorInstanceId: string; + expectedAsOfSequence: string; +} + +export interface AgentEventPageRequest extends ListAgentEventsRequest { + expectedOperatorInstanceId: string; + expectedAsOfSequence: string; + expectedRunId: string; + expectedNodeId: string; +} + +export interface LogDescriptorPage { + operatorInstanceId: string; + asOfSequence: string; + records: LogRecordDescriptorMsg[]; + nextPageToken: string; + nextCursor: string; +} + +export interface AgentEventDescriptorPage { + operatorInstanceId: string; + asOfSequence: string; + runId: string; + nodeId: string; + records: AgentEventDescriptorMsg[]; + nextPageToken: string; + nextCursor: string; +} + +export interface OperatorApi { + getCatalog(signal?: AbortSignal): Promise; + loadBaseline(signal?: AbortSignal): Promise; + getLatestRunSnapshot( + runId: string, + operatorInstanceId: string, + signal?: AbortSignal, + ): Promise; + streamUpdates( + operatorInstanceId: string, + afterSequence: string, + signal?: AbortSignal, + ): AsyncIterable; + listLogPage(request: LogPageRequest, signal?: AbortSignal): Promise; + listAgentEventPage( + request: AgentEventPageRequest, + signal?: AbortSignal, + ): Promise; + readJsonDetail(bodyToken: string, signal?: AbortSignal): Promise; + readTextDetail(bodyToken: string, signal?: AbortSignal): Promise; + startRun(workflowSelector: string, input?: Record): Promise; + cancelRun(runId: string): Promise; +} + +export class GrpcWebOperatorApi implements OperatorApi { + readonly client: OperatorServiceClient; + + constructor( + baseUrl = window.location.origin, + client?: OperatorServiceClient, + ) { + this.client = + client ?? + new OperatorServiceClient(new GrpcWebFetchTransport({ baseUrl, format: "binary" })); + } + + async getCatalog(signal?: AbortSignal): Promise { + return await this.client.getCatalog( + {}, + signal ? { abort: signal } : undefined, + ).response; + } + + async loadBaseline(signal?: AbortSignal): Promise { + const catalog = await this.getCatalog(signal); + const runs: RunSummaryMsg[] = []; + const seenPageTokens = new Set(); + let pageToken = ""; + let operatorInstanceId = ""; + let asOfSequence = "0"; + let summaryBytes = 0; + do { + if (seenPageTokens.size >= MAX_BASELINE_PAGES) { + throw new Error("Run baseline exceeds the page hydration budget"); + } + if (seenPageTokens.has(pageToken)) { + throw new Error("Run summary pagination made no progress"); + } + seenPageTokens.add(pageToken); + const page = await this.client.listRunSummaries( + { + workflowSelector: "", + pageSize: 100, + pageToken, + }, + signal ? { abort: signal } : undefined, + ).response; + if (!operatorInstanceId) { + operatorInstanceId = page.operatorInstanceId; + asOfSequence = page.asOfSequence; + } else if ( + page.operatorInstanceId !== operatorInstanceId || + page.asOfSequence !== asOfSequence + ) { + throw new Error("Run baseline changed while loading pages"); + } + for (const summary of page.runs) { + const encodedBytes = new TextEncoder().encode(JSON.stringify(summary)).byteLength; + if ( + runs.length >= MAX_BASELINE_SUMMARIES || + summaryBytes + encodedBytes > MAX_BASELINE_BYTES + ) { + throw new Error("Run baseline exceeds the hydration budget"); + } + runs.push(summary); + summaryBytes += encodedBytes; + } + pageToken = page.nextPageToken; + } while (pageToken); + + const confirmedCatalog = await this.getCatalog(signal); + if ( + catalog.operatorInstanceId !== operatorInstanceId || + confirmedCatalog.operatorInstanceId !== operatorInstanceId || + catalog.revision !== confirmedCatalog.revision || + BigInt(catalog.asOfSequence) > BigInt(asOfSequence) || + BigInt(confirmedCatalog.asOfSequence) < BigInt(asOfSequence) + ) { + throw new Error("Operator state changed while loading the browser baseline"); + } + return { catalog, asOfSequence, runs }; + } + + async getLatestRunSnapshot( + runId: string, + operatorInstanceId: string, + signal?: AbortSignal, + ): Promise { + return await this.client.getLatestRunSnapshot( + { runId, operatorInstanceId }, + signal ? { abort: signal } : undefined, + ).response; + } + + streamUpdates( + operatorInstanceId: string, + afterSequence: string, + signal?: AbortSignal, + ): AsyncIterable { + return this.client.streamOperatorUpdates( + { operatorInstanceId, afterSequence }, + signal ? { abort: signal } : undefined, + ).responses; + } + + async listLogPage( + request: LogPageRequest, + signal?: AbortSignal, + ): Promise { + const { + expectedOperatorInstanceId, + expectedAsOfSequence, + ...rpcRequest + } = request; + const page = await this.client.listLogs( + rpcRequest, + signal ? { abort: signal } : undefined, + ).response; + if ( + page.operatorInstanceId !== expectedOperatorInstanceId || + page.asOfSequence !== expectedAsOfSequence + ) { + throw new Error("Log page does not belong to the selected run snapshot"); + } + const currentCursor = + request.order === DescriptorPageOrder.NEWEST_FIRST + ? request.beforeSequence + : request.afterSequence; + const nextCursor = page.logs.at(-1)?.sequence ?? currentCursor; + assertPageProgress( + request.pageToken, + page.nextPageToken, + currentCursor, + nextCursor, + request.order, + page.logs.length, + "Log", + ); + return { + operatorInstanceId: page.operatorInstanceId, + asOfSequence: page.asOfSequence, + records: page.logs, + nextPageToken: page.nextPageToken, + nextCursor, + }; + } + + async listAgentEventPage( + request: AgentEventPageRequest, + signal?: AbortSignal, + ): Promise { + const { + expectedOperatorInstanceId, + expectedAsOfSequence, + expectedRunId, + expectedNodeId, + ...rpcRequest + } = request; + const page = await this.client.listAgentEvents( + rpcRequest, + signal ? { abort: signal } : undefined, + ).response; + if ( + page.operatorInstanceId !== expectedOperatorInstanceId || + page.asOfSequence !== expectedAsOfSequence || + page.runId !== expectedRunId || + page.nodeId !== expectedNodeId + ) { + throw new Error("Agent event page does not belong to the selected node snapshot"); + } + const currentCursor = + request.order === DescriptorPageOrder.NEWEST_FIRST + ? request.beforeEventSequence + : request.afterEventSequence; + const nextCursor = page.events.at(-1)?.eventSequence ?? currentCursor; + assertPageProgress( + request.pageToken, + page.nextPageToken, + currentCursor, + nextCursor, + request.order, + page.events.length, + "Agent event", + ); + return { + operatorInstanceId: page.operatorInstanceId, + asOfSequence: page.asOfSequence, + runId: page.runId, + nodeId: page.nodeId, + records: page.events, + nextPageToken: page.nextPageToken, + nextCursor, + }; + } + + async readJsonDetail(bodyToken: string, signal?: AbortSignal): Promise { + return JSON.parse(await this.readTextDetail(bodyToken, signal)); + } + + async readTextDetail(bodyToken: string, signal?: AbortSignal): Promise { + const decoder = new TextDecoder(); + const decoded: string[] = []; + for await (const chunk of this.client.readDetail( + { bodyToken }, + signal ? { abort: signal } : undefined, + ).responses) { + decoded.push(decoder.decode(chunk.data, { stream: true })); + } + decoded.push(decoder.decode()); + return decoded.join(""); + } + + async startRun( + workflowSelector: string, + input?: Record, + ): Promise { + const response = await this.client.startRun({ + workflowSelector, + runId: "", + inputJson: input === undefined ? "" : JSON.stringify(input), + contextJson: "", + inputFiles: [], + }).response; + return response.runId; + } + + async cancelRun(runId: string): Promise { + await this.client.cancelRun({ runId }).response; + } +} + + +function assertPageProgress( + pageToken: string, + nextPageToken: string, + currentCursor: string, + nextCursor: string, + order: DescriptorPageOrder, + recordCount: number, + kind: string, +): void { + if (!nextPageToken) return; + if ( + nextPageToken === pageToken || + recordCount === 0 || + nextCursor === currentCursor || + (order === DescriptorPageOrder.FORWARD && + BigInt(nextCursor) <= BigInt(currentCursor)) || + (order === DescriptorPageOrder.NEWEST_FIRST && + currentCursor !== "0" && + BigInt(nextCursor) >= BigInt(currentCursor)) + ) { + throw new Error(`${kind} pagination made no progress`); + } +} diff --git a/web/operator/src/detailProjection.ts b/web/operator/src/detailProjection.ts new file mode 100644 index 0000000..ab922e2 --- /dev/null +++ b/web/operator/src/detailProjection.ts @@ -0,0 +1,72 @@ +export type DescriptorRetention = "older" | "newer"; + +export interface DescriptorPageState { + records: T[]; + nextPageToken: string; + nextCursor: string; +} + +export const DESCRIPTOR_PAGE_SIZE = 100; +export const DESCRIPTOR_WINDOW_SIZE = 500; +export const DETAIL_CACHE_MAX_BYTES = 8 * 1024 * 1024; +export const SCROLL_LOAD_THRESHOLD_PX = 96; + +export function compareSequence(left: string, right: string) { + if (left.length !== right.length) return left.length - right.length; + return left < right ? -1 : left > right ? 1 : 0; +} + +export function boundDescriptors( + recordsBySequence: Map, + sequence: (record: T) => string, + retention: DescriptorRetention, + retainedSequences: Iterable = [], +): T[] { + const merged = [...recordsBySequence.values()].sort((left, right) => + compareSequence(sequence(left), sequence(right)), + ); + if (merged.length <= DESCRIPTOR_WINDOW_SIZE) return merged; + + const retained = new Set(retainedSequences); + const retainedRecords: T[] = []; + const availableRecords: T[] = []; + for (const record of merged) { + (retained.has(sequence(record)) ? retainedRecords : availableRecords).push(record); + } + return [ + ...(retention === "newer" + ? availableRecords.slice(-(DESCRIPTOR_WINDOW_SIZE - retainedRecords.length)) + : availableRecords.slice(0, DESCRIPTOR_WINDOW_SIZE - retainedRecords.length)), + ...retainedRecords, + ] + .sort((left, right) => compareSequence(sequence(left), sequence(right))) + .slice(-DESCRIPTOR_WINDOW_SIZE); +} + +export function mergeDescriptorPage( + current: DescriptorPageState, + next: DescriptorPageState, + sequence: (record: T) => string, + retention: DescriptorRetention, + retainedSequences: Iterable = [], +): DescriptorPageState { + const recordsBySequence = new Map(); + for (const record of current.records) recordsBySequence.set(sequence(record), record); + for (const record of next.records) recordsBySequence.set(sequence(record), record); + return { + ...next, + records: boundDescriptors(recordsBySequence, sequence, retention, retainedSequences), + }; +} + +export function measuredByteCost(value: unknown, reportedSize?: string) { + const reported = Number(reportedSize); + let measured = 0; + try { + const encoded = typeof value === "string" ? value : JSON.stringify(value) ?? ""; + measured = new TextEncoder().encode(encoded).byteLength; + } catch { + measured = DETAIL_CACHE_MAX_BYTES + 1; + } + return Math.max(Number.isFinite(reported) && reported > 0 ? reported : 0, measured); +} diff --git a/web/operator/src/generated/operator.client.ts b/web/operator/src/generated/operator.client.ts new file mode 100644 index 0000000..1e40f33 --- /dev/null +++ b/web/operator/src/generated/operator.client.ts @@ -0,0 +1,191 @@ +// @generated by protobuf-ts 2.11.1 with parameter long_type_string +// @generated from protobuf file "operator.proto" (package "avalanche.operator", syntax proto3) +// tslint:disable +import type { RpcTransport } from "@protobuf-ts/runtime-rpc"; +import type { ServiceInfo } from "@protobuf-ts/runtime-rpc"; +import { OperatorService } from "./operator"; +import type { OperatorUpdateEnvelope } from "./operator"; +import type { StreamOperatorUpdatesRequest } from "./operator"; +import type { DetailChunk } from "./operator"; +import type { ReadDetailRequest } from "./operator"; +import type { TraceChunk } from "./operator"; +import type { ReadTraceRequest } from "./operator"; +import type { ServerStreamingCall } from "@protobuf-ts/runtime-rpc"; +import type { AgentEventPage } from "./operator"; +import type { ListAgentEventsRequest } from "./operator"; +import type { LogPage } from "./operator"; +import type { ListLogsRequest } from "./operator"; +import type { GetLatestRunSnapshotRequest } from "./operator"; +import type { RunSnapshotMsg } from "./operator"; +import type { GetRunSnapshotRequest } from "./operator"; +import type { RunSummaryPage } from "./operator"; +import type { ListRunSummariesRequest } from "./operator"; +import type { RunResultMsg } from "./operator"; +import type { GetRunRequest } from "./operator"; +import type { CancelRunRequest } from "./operator"; +import type { StartRunResponse } from "./operator"; +import type { StartRunRequest } from "./operator"; +import { stackIntercept } from "@protobuf-ts/runtime-rpc"; +import type { CatalogSnapshotMsg } from "./operator"; +import type { Empty } from "./operator"; +import type { UnaryCall } from "@protobuf-ts/runtime-rpc"; +import type { RpcOptions } from "@protobuf-ts/runtime-rpc"; +// Breaking migration: the previous full-state run APIs are replaced by bounded +// summary, snapshot, detail, and typed update APIs below. Remote operators and +// clients must upgrade together. + +// ── Service ───────────────────────────────────────────── + +/** + * @generated from protobuf service avalanche.operator.OperatorService + */ +export interface IOperatorServiceClient { + /** + * @generated from protobuf rpc: GetCatalog + */ + getCatalog(input: Empty, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: StartRun + */ + startRun(input: StartRunRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: CancelRun + */ + cancelRun(input: CancelRunRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: GetRunResult + */ + getRunResult(input: GetRunRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: ListRunSummaries + */ + listRunSummaries(input: ListRunSummariesRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: GetRunSnapshot + */ + getRunSnapshot(input: GetRunSnapshotRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: GetLatestRunSnapshot + */ + getLatestRunSnapshot(input: GetLatestRunSnapshotRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: ListLogs + */ + listLogs(input: ListLogsRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: ListAgentEvents + */ + listAgentEvents(input: ListAgentEventsRequest, options?: RpcOptions): UnaryCall; + /** + * @generated from protobuf rpc: ReadTrace + */ + readTrace(input: ReadTraceRequest, options?: RpcOptions): ServerStreamingCall; + /** + * @generated from protobuf rpc: ReadDetail + */ + readDetail(input: ReadDetailRequest, options?: RpcOptions): ServerStreamingCall; + /** + * @generated from protobuf rpc: StreamOperatorUpdates + */ + streamOperatorUpdates(input: StreamOperatorUpdatesRequest, options?: RpcOptions): ServerStreamingCall; +} +// Breaking migration: the previous full-state run APIs are replaced by bounded +// summary, snapshot, detail, and typed update APIs below. Remote operators and +// clients must upgrade together. + +// ── Service ───────────────────────────────────────────── + +/** + * @generated from protobuf service avalanche.operator.OperatorService + */ +export class OperatorServiceClient implements IOperatorServiceClient, ServiceInfo { + typeName = OperatorService.typeName; + methods = OperatorService.methods; + options = OperatorService.options; + constructor(private readonly _transport: RpcTransport) { + } + /** + * @generated from protobuf rpc: GetCatalog + */ + getCatalog(input: Empty, options?: RpcOptions): UnaryCall { + const method = this.methods[0], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: StartRun + */ + startRun(input: StartRunRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[1], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: CancelRun + */ + cancelRun(input: CancelRunRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[2], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: GetRunResult + */ + getRunResult(input: GetRunRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[3], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: ListRunSummaries + */ + listRunSummaries(input: ListRunSummariesRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[4], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: GetRunSnapshot + */ + getRunSnapshot(input: GetRunSnapshotRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[5], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: GetLatestRunSnapshot + */ + getLatestRunSnapshot(input: GetLatestRunSnapshotRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[6], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: ListLogs + */ + listLogs(input: ListLogsRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[7], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: ListAgentEvents + */ + listAgentEvents(input: ListAgentEventsRequest, options?: RpcOptions): UnaryCall { + const method = this.methods[8], opt = this._transport.mergeOptions(options); + return stackIntercept("unary", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: ReadTrace + */ + readTrace(input: ReadTraceRequest, options?: RpcOptions): ServerStreamingCall { + const method = this.methods[9], opt = this._transport.mergeOptions(options); + return stackIntercept("serverStreaming", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: ReadDetail + */ + readDetail(input: ReadDetailRequest, options?: RpcOptions): ServerStreamingCall { + const method = this.methods[10], opt = this._transport.mergeOptions(options); + return stackIntercept("serverStreaming", this._transport, method, opt, input); + } + /** + * @generated from protobuf rpc: StreamOperatorUpdates + */ + streamOperatorUpdates(input: StreamOperatorUpdatesRequest, options?: RpcOptions): ServerStreamingCall { + const method = this.methods[11], opt = this._transport.mergeOptions(options); + return stackIntercept("serverStreaming", this._transport, method, opt, input); + } +} diff --git a/web/operator/src/generated/operator.ts b/web/operator/src/generated/operator.ts new file mode 100644 index 0000000..91f2020 --- /dev/null +++ b/web/operator/src/generated/operator.ts @@ -0,0 +1,4648 @@ +// @generated by protobuf-ts 2.11.1 with parameter long_type_string +// @generated from protobuf file "operator.proto" (package "avalanche.operator", syntax proto3) +// tslint:disable +import { ServiceType } from "@protobuf-ts/runtime-rpc"; +import { WireType } from "@protobuf-ts/runtime"; +import type { BinaryWriteOptions } from "@protobuf-ts/runtime"; +import type { IBinaryWriter } from "@protobuf-ts/runtime"; +import type { BinaryReadOptions } from "@protobuf-ts/runtime"; +import type { IBinaryReader } from "@protobuf-ts/runtime"; +import { UnknownFieldHandler } from "@protobuf-ts/runtime"; +import type { PartialMessage } from "@protobuf-ts/runtime"; +import { reflectionMergePartial } from "@protobuf-ts/runtime"; +import { MessageType } from "@protobuf-ts/runtime"; +// ── Request / Response ────────────────────────────────── + +/** + * @generated from protobuf message avalanche.operator.Empty + */ +export interface Empty { +} +/** + * @generated from protobuf message avalanche.operator.StartRunRequest + */ +export interface StartRunRequest { + /** + * @generated from protobuf field: string input_json = 2 + */ + inputJson: string; + /** + * @generated from protobuf field: string context_json = 3 + */ + contextJson: string; + /** + * @generated from protobuf field: repeated avalanche.operator.FileAttachment input_files = 4 + */ + inputFiles: FileAttachment[]; + /** + * @generated from protobuf field: string run_id = 6 + */ + runId: string; + /** + * @generated from protobuf field: string workflow_selector = 7 + */ + workflowSelector: string; +} +/** + * @generated from protobuf message avalanche.operator.FileAttachment + */ +export interface FileAttachment { + /** + * @generated from protobuf field: string field_name = 1 + */ + fieldName: string; + /** + * @generated from protobuf field: string name = 2 + */ + name: string; + /** + * @generated from protobuf field: bytes content = 3 + */ + content: Uint8Array; + /** + * @generated from protobuf field: string content_type = 4 + */ + contentType: string; + /** + * @generated from protobuf field: string sha256 = 5 + */ + sha256: string; +} +/** + * @generated from protobuf message avalanche.operator.StartRunResponse + */ +export interface StartRunResponse { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; +} +/** + * @generated from protobuf message avalanche.operator.CancelRunRequest + */ +export interface CancelRunRequest { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; +} +/** + * @generated from protobuf message avalanche.operator.GetRunRequest + */ +export interface GetRunRequest { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; +} +/** + * @generated from protobuf message avalanche.operator.ListRunSummariesRequest + */ +export interface ListRunSummariesRequest { + /** + * @generated from protobuf field: string workflow_selector = 1 + */ + workflowSelector: string; + /** + * @generated from protobuf field: uint32 page_size = 2 + */ + pageSize: number; + /** + * @generated from protobuf field: string page_token = 3 + */ + pageToken: string; +} +/** + * @generated from protobuf message avalanche.operator.GetRunSnapshotRequest + */ +export interface GetRunSnapshotRequest { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: string operator_instance_id = 2 + */ + operatorInstanceId: string; + /** + * @generated from protobuf field: uint64 as_of_sequence = 3 + */ + asOfSequence: string; +} +/** + * @generated from protobuf message avalanche.operator.GetLatestRunSnapshotRequest + */ +export interface GetLatestRunSnapshotRequest { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: string operator_instance_id = 2 + */ + operatorInstanceId: string; +} +/** + * Page tokens are opaque bearer references issued by GetRunSnapshot. The current + * loopback transport does not sign them; authenticated deployments must sign or + * tenant-bind tokens and reauthorize the referenced run on every use. + * + * @generated from protobuf message avalanche.operator.ListLogsRequest + */ +export interface ListLogsRequest { + /** + * Required snapshot-issued token. Cursors and filters are relative to this snapshot. + * + * @generated from protobuf field: string page_token = 1 + */ + pageToken: string; + /** + * Exclusive lower log bound for forward and incremental hydration. + * + * @generated from protobuf field: uint64 after_sequence = 2 + */ + afterSequence: string; + /** + * @generated from protobuf field: uint32 page_size = 3 + */ + pageSize: number; + /** + * Exclusive upper log bound for newest-first hydration; zero starts at the snapshot end. + * + * @generated from protobuf field: uint64 before_sequence = 4 + */ + beforeSequence: string; + /** + * Optional exact node filter. Continuation tokens bind this filter. + * + * @generated from protobuf field: string node_id = 5 + */ + nodeId: string; + /** + * @generated from protobuf field: avalanche.operator.DescriptorPageOrder order = 6 + */ + order: DescriptorPageOrder; +} +/** + * @generated from protobuf message avalanche.operator.ListAgentEventsRequest + */ +export interface ListAgentEventsRequest { + /** + * Required snapshot-issued token. Cursors are relative to this snapshot. + * + * @generated from protobuf field: string page_token = 1 + */ + pageToken: string; + /** + * Exclusive lower event bound for forward and incremental hydration. + * + * @generated from protobuf field: uint64 after_event_sequence = 2 + */ + afterEventSequence: string; + /** + * @generated from protobuf field: uint32 page_size = 3 + */ + pageSize: number; + /** + * Exclusive upper event bound for newest-first hydration; zero starts at the snapshot end. + * + * @generated from protobuf field: uint64 before_event_sequence = 4 + */ + beforeEventSequence: string; + /** + * @generated from protobuf field: avalanche.operator.DescriptorPageOrder order = 5 + */ + order: DescriptorPageOrder; +} +/** + * @generated from protobuf message avalanche.operator.ReadTraceRequest + */ +export interface ReadTraceRequest { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: string node_id = 2 + */ + nodeId: string; + /** + * @generated from protobuf field: uint64 revision = 3 + */ + revision: string; + /** + * @generated from protobuf field: string operator_instance_id = 4 + */ + operatorInstanceId: string; +} +/** + * @generated from protobuf message avalanche.operator.ReadDetailRequest + */ +export interface ReadDetailRequest { + /** + * @generated from protobuf field: string body_token = 1 + */ + bodyToken: string; +} +/** + * @generated from protobuf message avalanche.operator.StreamOperatorUpdatesRequest + */ +export interface StreamOperatorUpdatesRequest { + /** + * @generated from protobuf field: string operator_instance_id = 1 + */ + operatorInstanceId: string; + /** + * @generated from protobuf field: uint64 after_sequence = 2 + */ + afterSequence: string; +} +// ── Data Messages ─────────────────────────────────────── + +/** + * @generated from protobuf message avalanche.operator.NodeEdges + */ +export interface NodeEdges { + /** + * @generated from protobuf field: repeated string children = 1 + */ + children: string[]; +} +/** + * @generated from protobuf message avalanche.operator.WorkflowTopologyMsg + */ +export interface WorkflowTopologyMsg { + /** + * @generated from protobuf field: repeated string node_ids = 1 + */ + nodeIds: string[]; + /** + * @generated from protobuf field: map graph = 2 + */ + graph: { + [key: string]: NodeEdges; + }; + /** + * @generated from protobuf field: map node_types = 3 + */ + nodeTypes: { + [key: string]: string; + }; + /** + * @generated from protobuf field: map display_names = 4 + */ + displayNames: { + [key: string]: string; + }; + /** + * @generated from protobuf field: map agent_field_schemas_json = 5 + */ + agentFieldSchemasJson: { + [key: string]: string; + }; + /** + * @generated from protobuf field: map agent_instruction_lines = 6 + */ + agentInstructionLines: { + [key: string]: string; + }; +} +/** + * @generated from protobuf message avalanche.operator.FlowInfoMsg + */ +export interface FlowInfoMsg { + /** + * @generated from protobuf field: string name = 1 + */ + name: string; + /** + * @generated from protobuf field: string file_path = 2 + */ + filePath: string; + /** + * @generated from protobuf field: repeated string node_ids = 3 + */ + nodeIds: string[]; + /** + * @generated from protobuf field: map graph = 4 + */ + graph: { + [key: string]: NodeEdges; + }; + /** + * @generated from protobuf field: map node_types = 5 + */ + nodeTypes: { + [key: string]: string; + }; + /** + * @generated from protobuf field: map display_names = 6 + */ + displayNames: { + [key: string]: string; + }; + /** + * @generated from protobuf field: string cron = 7 + */ + cron: string; + /** + * @generated from protobuf field: double next_run_at = 8 + */ + nextRunAt: number; + /** + * @generated from protobuf field: double last_run_at = 9 + */ + lastRunAt: number; + /** + * @generated from protobuf field: string workflow_id = 10 + */ + workflowId: string; + /** + * @generated from protobuf field: string display_name = 11 + */ + displayName: string; + /** + * @generated from protobuf field: string root_alias = 12 + */ + rootAlias: string; + /** + * @generated from protobuf field: string relative_file = 13 + */ + relativeFile: string; + /** + * @generated from protobuf field: string builder_symbol = 14 + */ + builderSymbol: string; + /** + * @generated from protobuf field: repeated string agent_node_ids = 15 + */ + agentNodeIds: string[]; + /** + * @generated from protobuf field: map agent_metadata_json = 16 + */ + agentMetadataJson: { + [key: string]: string; + }; + /** + * @generated from protobuf field: string webhook_path = 17 + */ + webhookPath: string; + /** + * @generated from protobuf field: string webhook_url = 18 + */ + webhookUrl: string; + /** + * @generated from protobuf field: bool webhook_active = 19 + */ + webhookActive: boolean; +} +/** + * @generated from protobuf message avalanche.operator.DiscoveryDiagnosticMsg + */ +export interface DiscoveryDiagnosticMsg { + /** + * @generated from protobuf field: string path = 1 + */ + path: string; + /** + * @generated from protobuf field: string kind = 2 + */ + kind: string; + /** + * @generated from protobuf field: string message = 3 + */ + message: string; +} +/** + * @generated from protobuf message avalanche.operator.ScanTargetMsg + */ +export interface ScanTargetMsg { + /** + * @generated from protobuf field: string alias = 1 + */ + alias: string; + /** + * @generated from protobuf field: string target_path = 2 + */ + targetPath: string; + /** + * @generated from protobuf field: string kind = 3 + */ + kind: string; +} +/** + * @generated from protobuf message avalanche.operator.CatalogSnapshotMsg + */ +export interface CatalogSnapshotMsg { + /** + * @generated from protobuf field: string operator_instance_id = 1 + */ + operatorInstanceId: string; + /** + * @generated from protobuf field: uint64 as_of_sequence = 2 + */ + asOfSequence: string; + /** + * @generated from protobuf field: uint64 revision = 3 + */ + revision: string; + /** + * @generated from protobuf field: repeated avalanche.operator.FlowInfoMsg workflows = 4 + */ + workflows: FlowInfoMsg[]; + /** + * @generated from protobuf field: repeated avalanche.operator.ScanTargetMsg scan_targets = 5 + */ + scanTargets: ScanTargetMsg[]; + /** + * @generated from protobuf field: repeated avalanche.operator.DiscoveryDiagnosticMsg diagnostics = 6 + */ + diagnostics: DiscoveryDiagnosticMsg[]; +} +/** + * @generated from protobuf message avalanche.operator.ResultFileAttachment + */ +export interface ResultFileAttachment { + /** + * @generated from protobuf field: string attachment_id = 1 + */ + attachmentId: string; + /** + * @generated from protobuf field: optional string name = 2 + */ + name?: string; + /** + * @generated from protobuf field: bytes content = 3 + */ + content: Uint8Array; + /** + * @generated from protobuf field: optional string media_type = 4 + */ + mediaType?: string; + /** + * @generated from protobuf field: string sha256 = 5 + */ + sha256: string; +} +/** + * @generated from protobuf message avalanche.operator.RunResultMsg + */ +export interface RunResultMsg { + /** + * @generated from protobuf field: string value_json = 1 + */ + valueJson: string; + /** + * @generated from protobuf field: repeated avalanche.operator.ResultFileAttachment files = 2 + */ + files: ResultFileAttachment[]; +} +/** + * @generated from protobuf message avalanche.operator.RunSummaryMsg + */ +export interface RunSummaryMsg { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: string flow_name = 2 + */ + flowName: string; + /** + * @generated from protobuf field: string status = 3 + */ + status: string; + /** + * @generated from protobuf field: double started_at = 4 + */ + startedAt: number; + /** + * @generated from protobuf field: double ended_at = 5 + */ + endedAt: number; + /** + * @generated from protobuf field: string triggered_by = 6 + */ + triggeredBy: string; + /** + * @generated from protobuf field: string workflow_id = 7 + */ + workflowId: string; + /** + * @generated from protobuf field: string workflow_display_name = 8 + */ + workflowDisplayName: string; + /** + * @generated from protobuf field: uint64 created_sequence = 9 + */ + createdSequence: string; + /** + * @generated from protobuf field: uint64 revision = 10 + */ + revision: string; + /** + * @generated from protobuf field: double triggered_at = 11 + */ + triggeredAt: number; +} +/** + * @generated from protobuf message avalanche.operator.TraceHeaderMsg + */ +export interface TraceHeaderMsg { + /** + * @generated from protobuf field: string status = 1 + */ + status: string; + /** + * @generated from protobuf field: string model = 2 + */ + model: string; + /** + * @generated from protobuf field: optional string sub_model = 3 + */ + subModel?: string; + /** + * @generated from protobuf field: uint64 iterations = 4 + */ + iterations: string; + /** + * @generated from protobuf field: uint64 max_iterations = 5 + */ + maxIterations: string; + /** + * @generated from protobuf field: uint64 duration_ms = 6 + */ + durationMs: string; + /** + * @generated from protobuf field: string usage_json = 7 + */ + usageJson: string; + /** + * @generated from protobuf field: optional string telemetry_json = 8 + */ + telemetryJson?: string; +} +/** + * @generated from protobuf message avalanche.operator.TraceDescriptorMsg + */ +export interface TraceDescriptorMsg { + /** + * @generated from protobuf field: string status = 1 + */ + status: string; + /** + * @generated from protobuf field: uint64 revision = 2 + */ + revision: string; + /** + * @generated from protobuf field: bool available = 3 + */ + available: boolean; + /** + * @generated from protobuf field: bool complete = 4 + */ + complete: boolean; + /** + * @generated from protobuf field: uint64 event_count = 5 + */ + eventCount: string; + /** + * @generated from protobuf field: uint64 size_bytes = 6 + */ + sizeBytes: string; + /** + * @generated from protobuf field: uint64 latest_event_sequence = 7 + */ + latestEventSequence: string; + /** + * @generated from protobuf field: avalanche.operator.TraceHeaderMsg header = 8 + */ + header?: TraceHeaderMsg; +} +/** + * @generated from protobuf message avalanche.operator.NodeSnapshotMsg + */ +export interface NodeSnapshotMsg { + /** + * @generated from protobuf field: string node_id = 1 + */ + nodeId: string; + /** + * @generated from protobuf field: string name = 2 + */ + name: string; + /** + * @generated from protobuf field: string node_type = 3 + */ + nodeType: string; + /** + * @generated from protobuf field: string status = 4 + */ + status: string; + /** + * @generated from protobuf field: double started_at = 5 + */ + startedAt: number; + /** + * @generated from protobuf field: double ended_at = 6 + */ + endedAt: number; + /** + * @generated from protobuf field: avalanche.operator.TraceDescriptorMsg trace = 7 + */ + trace?: TraceDescriptorMsg; + /** + * @generated from protobuf field: uint64 revision = 8 + */ + revision: string; + /** + * @generated from protobuf field: string event_page_token = 9 + */ + eventPageToken: string; + /** + * @generated from protobuf field: optional string error = 10 + */ + error?: string; + /** + * @generated from protobuf field: optional double running_elapsed_seconds = 11 + */ + runningElapsedSeconds?: number; +} +/** + * @generated from protobuf message avalanche.operator.RunSnapshotMsg + */ +export interface RunSnapshotMsg { + /** + * @generated from protobuf field: string operator_instance_id = 1 + */ + operatorInstanceId: string; + /** + * @generated from protobuf field: uint64 as_of_sequence = 2 + */ + asOfSequence: string; + /** + * @generated from protobuf field: avalanche.operator.RunSummaryMsg summary = 3 + */ + summary?: RunSummaryMsg; + /** + * @generated from protobuf field: repeated avalanche.operator.NodeSnapshotMsg nodes = 4 + */ + nodes: NodeSnapshotMsg[]; + /** + * @generated from protobuf field: uint64 latest_log_sequence = 5 + */ + latestLogSequence: string; + /** + * @generated from protobuf field: string log_page_token = 6 + */ + logPageToken: string; + /** + * @generated from protobuf field: avalanche.operator.WorkflowTopologyMsg topology = 7 + */ + topology?: WorkflowTopologyMsg; +} +/** + * @generated from protobuf message avalanche.operator.RunSummaryPage + */ +export interface RunSummaryPage { + /** + * @generated from protobuf field: string operator_instance_id = 1 + */ + operatorInstanceId: string; + /** + * @generated from protobuf field: uint64 as_of_sequence = 2 + */ + asOfSequence: string; + /** + * @generated from protobuf field: repeated avalanche.operator.RunSummaryMsg runs = 3 + */ + runs: RunSummaryMsg[]; + /** + * @generated from protobuf field: string next_page_token = 4 + */ + nextPageToken: string; +} +/** + * @generated from protobuf message avalanche.operator.LogRecordDescriptorMsg + */ +export interface LogRecordDescriptorMsg { + /** + * @generated from protobuf field: uint64 sequence = 1 + */ + sequence: string; + /** + * @generated from protobuf field: double timestamp = 2 + */ + timestamp: number; + /** + * @generated from protobuf field: string level = 3 + */ + level: string; + /** + * @generated from protobuf field: string node_id = 4 + */ + nodeId: string; + /** + * @generated from protobuf field: uint64 size_bytes = 5 + */ + sizeBytes: string; + /** + * @generated from protobuf field: string body_token = 6 + */ + bodyToken: string; +} +/** + * @generated from protobuf message avalanche.operator.LogPage + */ +export interface LogPage { + /** + * @generated from protobuf field: string operator_instance_id = 1 + */ + operatorInstanceId: string; + /** + * @generated from protobuf field: uint64 as_of_sequence = 2 + */ + asOfSequence: string; + /** + * @generated from protobuf field: repeated avalanche.operator.LogRecordDescriptorMsg logs = 3 + */ + logs: LogRecordDescriptorMsg[]; + /** + * @generated from protobuf field: string next_page_token = 4 + */ + nextPageToken: string; +} +/** + * @generated from protobuf message avalanche.operator.AgentEventDescriptorMsg + */ +export interface AgentEventDescriptorMsg { + /** + * @generated from protobuf field: uint64 event_sequence = 1 + */ + eventSequence: string; + /** + * @generated from protobuf field: uint64 size_bytes = 2 + */ + sizeBytes: string; + /** + * @generated from protobuf field: string body_token = 3 + */ + bodyToken: string; + /** + * @generated from protobuf field: string invocation_id = 4 + */ + invocationId: string; + /** + * @generated from protobuf field: string event_kind = 5 + */ + eventKind: string; + /** + * @generated from protobuf field: optional uint32 iteration = 6 + */ + iteration?: number; + /** + * @generated from protobuf field: optional uint64 duration_ms = 7 + */ + durationMs?: string; + /** + * @generated from protobuf field: bool error = 8 + */ + error: boolean; + /** + * @generated from protobuf field: uint32 tool_count = 9 + */ + toolCount: number; + /** + * @generated from protobuf field: uint32 predict_count = 10 + */ + predictCount: number; +} +/** + * @generated from protobuf message avalanche.operator.AgentEventPage + */ +export interface AgentEventPage { + /** + * @generated from protobuf field: string operator_instance_id = 1 + */ + operatorInstanceId: string; + /** + * @generated from protobuf field: uint64 as_of_sequence = 2 + */ + asOfSequence: string; + /** + * @generated from protobuf field: string run_id = 3 + */ + runId: string; + /** + * @generated from protobuf field: string node_id = 4 + */ + nodeId: string; + /** + * @generated from protobuf field: repeated avalanche.operator.AgentEventDescriptorMsg events = 5 + */ + events: AgentEventDescriptorMsg[]; + /** + * @generated from protobuf field: string next_page_token = 6 + */ + nextPageToken: string; +} +/** + * @generated from protobuf message avalanche.operator.TraceChunk + */ +export interface TraceChunk { + /** + * @generated from protobuf field: uint64 revision = 1 + */ + revision: string; + /** + * @generated from protobuf field: uint64 chunk_index = 2 + */ + chunkIndex: string; + /** + * @generated from protobuf field: bytes data = 3 + */ + data: Uint8Array; + /** + * @generated from protobuf field: bool eof = 4 + */ + eof: boolean; +} +/** + * @generated from protobuf message avalanche.operator.DetailChunk + */ +export interface DetailChunk { + /** + * @generated from protobuf field: uint64 chunk_index = 1 + */ + chunkIndex: string; + /** + * @generated from protobuf field: bytes data = 2 + */ + data: Uint8Array; + /** + * @generated from protobuf field: bool eof = 3 + */ + eof: boolean; +} +/** + * @generated from protobuf message avalanche.operator.RunCreated + */ +export interface RunCreated { + /** + * @generated from protobuf field: avalanche.operator.RunSummaryMsg summary = 1 + */ + summary?: RunSummaryMsg; + /** + * @generated from protobuf field: repeated avalanche.operator.NodeSnapshotMsg nodes = 2 + */ + nodes: NodeSnapshotMsg[]; + /** + * @generated from protobuf field: avalanche.operator.WorkflowTopologyMsg topology = 3 + */ + topology?: WorkflowTopologyMsg; +} +/** + * @generated from protobuf message avalanche.operator.RunStatusChanged + */ +export interface RunStatusChanged { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: string status = 2 + */ + status: string; + /** + * @generated from protobuf field: double started_at = 3 + */ + startedAt: number; + /** + * @generated from protobuf field: double ended_at = 4 + */ + endedAt: number; + /** + * @generated from protobuf field: uint64 revision = 5 + */ + revision: string; +} +/** + * @generated from protobuf message avalanche.operator.NodeStatusChanged + */ +export interface NodeStatusChanged { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: string node_id = 2 + */ + nodeId: string; + /** + * @generated from protobuf field: string status = 3 + */ + status: string; + /** + * @generated from protobuf field: double started_at = 4 + */ + startedAt: number; + /** + * @generated from protobuf field: double ended_at = 5 + */ + endedAt: number; + /** + * @generated from protobuf field: uint64 revision = 6 + */ + revision: string; + /** + * @generated from protobuf field: optional string error = 7 + */ + error?: string; + /** + * @generated from protobuf field: optional double running_elapsed_seconds = 8 + */ + runningElapsedSeconds?: number; +} +/** + * @generated from protobuf message avalanche.operator.LogAppended + */ +export interface LogAppended { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: avalanche.operator.LogRecordDescriptorMsg log = 2 + */ + log?: LogRecordDescriptorMsg; +} +/** + * @generated from protobuf message avalanche.operator.AgentEventAppended + */ +export interface AgentEventAppended { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: string node_id = 2 + */ + nodeId: string; + /** + * @generated from protobuf field: avalanche.operator.AgentEventDescriptorMsg event = 3 + */ + event?: AgentEventDescriptorMsg; +} +/** + * @generated from protobuf message avalanche.operator.TraceFinalized + */ +export interface TraceFinalized { + /** + * @generated from protobuf field: string run_id = 1 + */ + runId: string; + /** + * @generated from protobuf field: string node_id = 2 + */ + nodeId: string; + /** + * @generated from protobuf field: avalanche.operator.TraceDescriptorMsg trace = 3 + */ + trace?: TraceDescriptorMsg; +} +/** + * @generated from protobuf message avalanche.operator.CatalogReplaced + */ +export interface CatalogReplaced { + /** + * @generated from protobuf field: avalanche.operator.CatalogSnapshotMsg catalog = 1 + */ + catalog?: CatalogSnapshotMsg; +} +/** + * @generated from protobuf message avalanche.operator.OperatorUpdate + */ +export interface OperatorUpdate { + /** + * @generated from protobuf field: uint64 sequence = 1 + */ + sequence: string; + /** + * @generated from protobuf oneof: change + */ + change: { + oneofKind: "runCreated"; + /** + * @generated from protobuf field: avalanche.operator.RunCreated run_created = 2 + */ + runCreated: RunCreated; + } | { + oneofKind: "runStatusChanged"; + /** + * @generated from protobuf field: avalanche.operator.RunStatusChanged run_status_changed = 3 + */ + runStatusChanged: RunStatusChanged; + } | { + oneofKind: "nodeStatusChanged"; + /** + * @generated from protobuf field: avalanche.operator.NodeStatusChanged node_status_changed = 4 + */ + nodeStatusChanged: NodeStatusChanged; + } | { + oneofKind: "logAppended"; + /** + * @generated from protobuf field: avalanche.operator.LogAppended log_appended = 5 + */ + logAppended: LogAppended; + } | { + oneofKind: "agentEventAppended"; + /** + * @generated from protobuf field: avalanche.operator.AgentEventAppended agent_event_appended = 6 + */ + agentEventAppended: AgentEventAppended; + } | { + oneofKind: "traceFinalized"; + /** + * @generated from protobuf field: avalanche.operator.TraceFinalized trace_finalized = 7 + */ + traceFinalized: TraceFinalized; + } | { + oneofKind: "catalogReplaced"; + /** + * @generated from protobuf field: avalanche.operator.CatalogReplaced catalog_replaced = 8 + */ + catalogReplaced: CatalogReplaced; + } | { + oneofKind: undefined; + }; +} +/** + * @generated from protobuf message avalanche.operator.ResetRequired + */ +export interface ResetRequired { + /** + * @generated from protobuf field: uint64 history_floor = 1 + */ + historyFloor: string; + /** + * @generated from protobuf field: uint64 latest_sequence = 2 + */ + latestSequence: string; +} +/** + * @generated from protobuf message avalanche.operator.OperatorUpdateEnvelope + */ +export interface OperatorUpdateEnvelope { + /** + * @generated from protobuf field: string operator_instance_id = 1 + */ + operatorInstanceId: string; + /** + * @generated from protobuf oneof: payload + */ + payload: { + oneofKind: "update"; + /** + * @generated from protobuf field: avalanche.operator.OperatorUpdate update = 2 + */ + update: OperatorUpdate; + } | { + oneofKind: "resetRequired"; + /** + * @generated from protobuf field: avalanche.operator.ResetRequired reset_required = 3 + */ + resetRequired: ResetRequired; + } | { + oneofKind: undefined; + }; +} +/** + * @generated from protobuf enum avalanche.operator.DescriptorPageOrder + */ +export enum DescriptorPageOrder { + /** + * @generated from protobuf enum value: DESCRIPTOR_PAGE_ORDER_FORWARD = 0; + */ + FORWARD = 0, + /** + * @generated from protobuf enum value: DESCRIPTOR_PAGE_ORDER_NEWEST_FIRST = 1; + */ + NEWEST_FIRST = 1 +} +// @generated message type with reflection information, may provide speed optimized methods +class Empty$Type extends MessageType { + constructor() { + super("avalanche.operator.Empty", []); + } + create(value?: PartialMessage): Empty { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: Empty): Empty { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: Empty, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.Empty + */ +export const Empty = new Empty$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class StartRunRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.StartRunRequest", [ + { no: 2, name: "input_json", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "context_json", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "input_files", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => FileAttachment }, + { no: 6, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 7, name: "workflow_selector", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): StartRunRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.inputJson = ""; + message.contextJson = ""; + message.inputFiles = []; + message.runId = ""; + message.workflowSelector = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StartRunRequest): StartRunRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string input_json */ 2: + message.inputJson = reader.string(); + break; + case /* string context_json */ 3: + message.contextJson = reader.string(); + break; + case /* repeated avalanche.operator.FileAttachment input_files */ 4: + message.inputFiles.push(FileAttachment.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* string run_id */ 6: + message.runId = reader.string(); + break; + case /* string workflow_selector */ 7: + message.workflowSelector = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: StartRunRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string input_json = 2; */ + if (message.inputJson !== "") + writer.tag(2, WireType.LengthDelimited).string(message.inputJson); + /* string context_json = 3; */ + if (message.contextJson !== "") + writer.tag(3, WireType.LengthDelimited).string(message.contextJson); + /* repeated avalanche.operator.FileAttachment input_files = 4; */ + for (let i = 0; i < message.inputFiles.length; i++) + FileAttachment.internalBinaryWrite(message.inputFiles[i], writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* string run_id = 6; */ + if (message.runId !== "") + writer.tag(6, WireType.LengthDelimited).string(message.runId); + /* string workflow_selector = 7; */ + if (message.workflowSelector !== "") + writer.tag(7, WireType.LengthDelimited).string(message.workflowSelector); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.StartRunRequest + */ +export const StartRunRequest = new StartRunRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class FileAttachment$Type extends MessageType { + constructor() { + super("avalanche.operator.FileAttachment", [ + { no: 1, name: "field_name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "content", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 4, name: "content_type", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "sha256", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): FileAttachment { + const message = globalThis.Object.create((this.messagePrototype!)); + message.fieldName = ""; + message.name = ""; + message.content = new Uint8Array(0); + message.contentType = ""; + message.sha256 = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FileAttachment): FileAttachment { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string field_name */ 1: + message.fieldName = reader.string(); + break; + case /* string name */ 2: + message.name = reader.string(); + break; + case /* bytes content */ 3: + message.content = reader.bytes(); + break; + case /* string content_type */ 4: + message.contentType = reader.string(); + break; + case /* string sha256 */ 5: + message.sha256 = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: FileAttachment, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string field_name = 1; */ + if (message.fieldName !== "") + writer.tag(1, WireType.LengthDelimited).string(message.fieldName); + /* string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* bytes content = 3; */ + if (message.content.length) + writer.tag(3, WireType.LengthDelimited).bytes(message.content); + /* string content_type = 4; */ + if (message.contentType !== "") + writer.tag(4, WireType.LengthDelimited).string(message.contentType); + /* string sha256 = 5; */ + if (message.sha256 !== "") + writer.tag(5, WireType.LengthDelimited).string(message.sha256); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.FileAttachment + */ +export const FileAttachment = new FileAttachment$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class StartRunResponse$Type extends MessageType { + constructor() { + super("avalanche.operator.StartRunResponse", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): StartRunResponse { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StartRunResponse): StartRunResponse { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: StartRunResponse, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.StartRunResponse + */ +export const StartRunResponse = new StartRunResponse$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class CancelRunRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.CancelRunRequest", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): CancelRunRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CancelRunRequest): CancelRunRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: CancelRunRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.CancelRunRequest + */ +export const CancelRunRequest = new CancelRunRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetRunRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.GetRunRequest", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GetRunRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetRunRequest): GetRunRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetRunRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.GetRunRequest + */ +export const GetRunRequest = new GetRunRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ListRunSummariesRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.ListRunSummariesRequest", [ + { no: 1, name: "workflow_selector", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "page_size", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 3, name: "page_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ListRunSummariesRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.workflowSelector = ""; + message.pageSize = 0; + message.pageToken = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListRunSummariesRequest): ListRunSummariesRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string workflow_selector */ 1: + message.workflowSelector = reader.string(); + break; + case /* uint32 page_size */ 2: + message.pageSize = reader.uint32(); + break; + case /* string page_token */ 3: + message.pageToken = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ListRunSummariesRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string workflow_selector = 1; */ + if (message.workflowSelector !== "") + writer.tag(1, WireType.LengthDelimited).string(message.workflowSelector); + /* uint32 page_size = 2; */ + if (message.pageSize !== 0) + writer.tag(2, WireType.Varint).uint32(message.pageSize); + /* string page_token = 3; */ + if (message.pageToken !== "") + writer.tag(3, WireType.LengthDelimited).string(message.pageToken); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.ListRunSummariesRequest + */ +export const ListRunSummariesRequest = new ListRunSummariesRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetRunSnapshotRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.GetRunSnapshotRequest", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "as_of_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ } + ]); + } + create(value?: PartialMessage): GetRunSnapshotRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + message.operatorInstanceId = ""; + message.asOfSequence = "0"; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetRunSnapshotRequest): GetRunSnapshotRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* string operator_instance_id */ 2: + message.operatorInstanceId = reader.string(); + break; + case /* uint64 as_of_sequence */ 3: + message.asOfSequence = reader.uint64().toString(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetRunSnapshotRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* string operator_instance_id = 2; */ + if (message.operatorInstanceId !== "") + writer.tag(2, WireType.LengthDelimited).string(message.operatorInstanceId); + /* uint64 as_of_sequence = 3; */ + if (message.asOfSequence !== "0") + writer.tag(3, WireType.Varint).uint64(message.asOfSequence); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.GetRunSnapshotRequest + */ +export const GetRunSnapshotRequest = new GetRunSnapshotRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class GetLatestRunSnapshotRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.GetLatestRunSnapshotRequest", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): GetLatestRunSnapshotRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + message.operatorInstanceId = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: GetLatestRunSnapshotRequest): GetLatestRunSnapshotRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* string operator_instance_id */ 2: + message.operatorInstanceId = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: GetLatestRunSnapshotRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* string operator_instance_id = 2; */ + if (message.operatorInstanceId !== "") + writer.tag(2, WireType.LengthDelimited).string(message.operatorInstanceId); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.GetLatestRunSnapshotRequest + */ +export const GetLatestRunSnapshotRequest = new GetLatestRunSnapshotRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ListLogsRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.ListLogsRequest", [ + { no: 1, name: "page_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "after_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "page_size", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 4, name: "before_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 5, name: "node_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 6, name: "order", kind: "enum", T: () => ["avalanche.operator.DescriptorPageOrder", DescriptorPageOrder, "DESCRIPTOR_PAGE_ORDER_"] } + ]); + } + create(value?: PartialMessage): ListLogsRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.pageToken = ""; + message.afterSequence = "0"; + message.pageSize = 0; + message.beforeSequence = "0"; + message.nodeId = ""; + message.order = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListLogsRequest): ListLogsRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string page_token */ 1: + message.pageToken = reader.string(); + break; + case /* uint64 after_sequence */ 2: + message.afterSequence = reader.uint64().toString(); + break; + case /* uint32 page_size */ 3: + message.pageSize = reader.uint32(); + break; + case /* uint64 before_sequence */ 4: + message.beforeSequence = reader.uint64().toString(); + break; + case /* string node_id */ 5: + message.nodeId = reader.string(); + break; + case /* avalanche.operator.DescriptorPageOrder order */ 6: + message.order = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ListLogsRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string page_token = 1; */ + if (message.pageToken !== "") + writer.tag(1, WireType.LengthDelimited).string(message.pageToken); + /* uint64 after_sequence = 2; */ + if (message.afterSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.afterSequence); + /* uint32 page_size = 3; */ + if (message.pageSize !== 0) + writer.tag(3, WireType.Varint).uint32(message.pageSize); + /* uint64 before_sequence = 4; */ + if (message.beforeSequence !== "0") + writer.tag(4, WireType.Varint).uint64(message.beforeSequence); + /* string node_id = 5; */ + if (message.nodeId !== "") + writer.tag(5, WireType.LengthDelimited).string(message.nodeId); + /* avalanche.operator.DescriptorPageOrder order = 6; */ + if (message.order !== 0) + writer.tag(6, WireType.Varint).int32(message.order); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.ListLogsRequest + */ +export const ListLogsRequest = new ListLogsRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ListAgentEventsRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.ListAgentEventsRequest", [ + { no: 1, name: "page_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "after_event_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "page_size", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 4, name: "before_event_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 5, name: "order", kind: "enum", T: () => ["avalanche.operator.DescriptorPageOrder", DescriptorPageOrder, "DESCRIPTOR_PAGE_ORDER_"] } + ]); + } + create(value?: PartialMessage): ListAgentEventsRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.pageToken = ""; + message.afterEventSequence = "0"; + message.pageSize = 0; + message.beforeEventSequence = "0"; + message.order = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ListAgentEventsRequest): ListAgentEventsRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string page_token */ 1: + message.pageToken = reader.string(); + break; + case /* uint64 after_event_sequence */ 2: + message.afterEventSequence = reader.uint64().toString(); + break; + case /* uint32 page_size */ 3: + message.pageSize = reader.uint32(); + break; + case /* uint64 before_event_sequence */ 4: + message.beforeEventSequence = reader.uint64().toString(); + break; + case /* avalanche.operator.DescriptorPageOrder order */ 5: + message.order = reader.int32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ListAgentEventsRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string page_token = 1; */ + if (message.pageToken !== "") + writer.tag(1, WireType.LengthDelimited).string(message.pageToken); + /* uint64 after_event_sequence = 2; */ + if (message.afterEventSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.afterEventSequence); + /* uint32 page_size = 3; */ + if (message.pageSize !== 0) + writer.tag(3, WireType.Varint).uint32(message.pageSize); + /* uint64 before_event_sequence = 4; */ + if (message.beforeEventSequence !== "0") + writer.tag(4, WireType.Varint).uint64(message.beforeEventSequence); + /* avalanche.operator.DescriptorPageOrder order = 5; */ + if (message.order !== 0) + writer.tag(5, WireType.Varint).int32(message.order); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.ListAgentEventsRequest + */ +export const ListAgentEventsRequest = new ListAgentEventsRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ReadTraceRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.ReadTraceRequest", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "node_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "revision", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 4, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ReadTraceRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + message.nodeId = ""; + message.revision = "0"; + message.operatorInstanceId = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ReadTraceRequest): ReadTraceRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* string node_id */ 2: + message.nodeId = reader.string(); + break; + case /* uint64 revision */ 3: + message.revision = reader.uint64().toString(); + break; + case /* string operator_instance_id */ 4: + message.operatorInstanceId = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ReadTraceRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* string node_id = 2; */ + if (message.nodeId !== "") + writer.tag(2, WireType.LengthDelimited).string(message.nodeId); + /* uint64 revision = 3; */ + if (message.revision !== "0") + writer.tag(3, WireType.Varint).uint64(message.revision); + /* string operator_instance_id = 4; */ + if (message.operatorInstanceId !== "") + writer.tag(4, WireType.LengthDelimited).string(message.operatorInstanceId); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.ReadTraceRequest + */ +export const ReadTraceRequest = new ReadTraceRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ReadDetailRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.ReadDetailRequest", [ + { no: 1, name: "body_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ReadDetailRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.bodyToken = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ReadDetailRequest): ReadDetailRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string body_token */ 1: + message.bodyToken = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ReadDetailRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string body_token = 1; */ + if (message.bodyToken !== "") + writer.tag(1, WireType.LengthDelimited).string(message.bodyToken); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.ReadDetailRequest + */ +export const ReadDetailRequest = new ReadDetailRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class StreamOperatorUpdatesRequest$Type extends MessageType { + constructor() { + super("avalanche.operator.StreamOperatorUpdatesRequest", [ + { no: 1, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "after_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ } + ]); + } + create(value?: PartialMessage): StreamOperatorUpdatesRequest { + const message = globalThis.Object.create((this.messagePrototype!)); + message.operatorInstanceId = ""; + message.afterSequence = "0"; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: StreamOperatorUpdatesRequest): StreamOperatorUpdatesRequest { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string operator_instance_id */ 1: + message.operatorInstanceId = reader.string(); + break; + case /* uint64 after_sequence */ 2: + message.afterSequence = reader.uint64().toString(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: StreamOperatorUpdatesRequest, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string operator_instance_id = 1; */ + if (message.operatorInstanceId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.operatorInstanceId); + /* uint64 after_sequence = 2; */ + if (message.afterSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.afterSequence); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.StreamOperatorUpdatesRequest + */ +export const StreamOperatorUpdatesRequest = new StreamOperatorUpdatesRequest$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class NodeEdges$Type extends MessageType { + constructor() { + super("avalanche.operator.NodeEdges", [ + { no: 1, name: "children", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): NodeEdges { + const message = globalThis.Object.create((this.messagePrototype!)); + message.children = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: NodeEdges): NodeEdges { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated string children */ 1: + message.children.push(reader.string()); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: NodeEdges, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated string children = 1; */ + for (let i = 0; i < message.children.length; i++) + writer.tag(1, WireType.LengthDelimited).string(message.children[i]); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.NodeEdges + */ +export const NodeEdges = new NodeEdges$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class WorkflowTopologyMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.WorkflowTopologyMsg", [ + { no: 1, name: "node_ids", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "graph", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "message", T: () => NodeEdges } }, + { no: 3, name: "node_types", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } }, + { no: 4, name: "display_names", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } }, + { no: 5, name: "agent_field_schemas_json", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } }, + { no: 6, name: "agent_instruction_lines", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } } + ]); + } + create(value?: PartialMessage): WorkflowTopologyMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.nodeIds = []; + message.graph = {}; + message.nodeTypes = {}; + message.displayNames = {}; + message.agentFieldSchemasJson = {}; + message.agentInstructionLines = {}; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: WorkflowTopologyMsg): WorkflowTopologyMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* repeated string node_ids */ 1: + message.nodeIds.push(reader.string()); + break; + case /* map graph */ 2: + this.binaryReadMap2(message.graph, reader, options); + break; + case /* map node_types */ 3: + this.binaryReadMap3(message.nodeTypes, reader, options); + break; + case /* map display_names */ 4: + this.binaryReadMap4(message.displayNames, reader, options); + break; + case /* map agent_field_schemas_json */ 5: + this.binaryReadMap5(message.agentFieldSchemasJson, reader, options); + break; + case /* map agent_instruction_lines */ 6: + this.binaryReadMap6(message.agentInstructionLines, reader, options); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + private binaryReadMap2(map: WorkflowTopologyMsg["graph"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof WorkflowTopologyMsg["graph"] | undefined, val: WorkflowTopologyMsg["graph"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = NodeEdges.internalBinaryRead(reader, reader.uint32(), options); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.WorkflowTopologyMsg.graph"); + } + } + map[key ?? ""] = val ?? NodeEdges.create(); + } + private binaryReadMap3(map: WorkflowTopologyMsg["nodeTypes"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof WorkflowTopologyMsg["nodeTypes"] | undefined, val: WorkflowTopologyMsg["nodeTypes"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = reader.string(); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.WorkflowTopologyMsg.node_types"); + } + } + map[key ?? ""] = val ?? ""; + } + private binaryReadMap4(map: WorkflowTopologyMsg["displayNames"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof WorkflowTopologyMsg["displayNames"] | undefined, val: WorkflowTopologyMsg["displayNames"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = reader.string(); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.WorkflowTopologyMsg.display_names"); + } + } + map[key ?? ""] = val ?? ""; + } + private binaryReadMap5(map: WorkflowTopologyMsg["agentFieldSchemasJson"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof WorkflowTopologyMsg["agentFieldSchemasJson"] | undefined, val: WorkflowTopologyMsg["agentFieldSchemasJson"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = reader.string(); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.WorkflowTopologyMsg.agent_field_schemas_json"); + } + } + map[key ?? ""] = val ?? ""; + } + private binaryReadMap6(map: WorkflowTopologyMsg["agentInstructionLines"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof WorkflowTopologyMsg["agentInstructionLines"] | undefined, val: WorkflowTopologyMsg["agentInstructionLines"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = reader.string(); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.WorkflowTopologyMsg.agent_instruction_lines"); + } + } + map[key ?? ""] = val ?? ""; + } + internalBinaryWrite(message: WorkflowTopologyMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* repeated string node_ids = 1; */ + for (let i = 0; i < message.nodeIds.length; i++) + writer.tag(1, WireType.LengthDelimited).string(message.nodeIds[i]); + /* map graph = 2; */ + for (let k of globalThis.Object.keys(message.graph)) { + writer.tag(2, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k); + writer.tag(2, WireType.LengthDelimited).fork(); + NodeEdges.internalBinaryWrite(message.graph[k], writer, options); + writer.join().join(); + } + /* map node_types = 3; */ + for (let k of globalThis.Object.keys(message.nodeTypes)) + writer.tag(3, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k).tag(2, WireType.LengthDelimited).string(message.nodeTypes[k]).join(); + /* map display_names = 4; */ + for (let k of globalThis.Object.keys(message.displayNames)) + writer.tag(4, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k).tag(2, WireType.LengthDelimited).string(message.displayNames[k]).join(); + /* map agent_field_schemas_json = 5; */ + for (let k of globalThis.Object.keys(message.agentFieldSchemasJson)) + writer.tag(5, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k).tag(2, WireType.LengthDelimited).string(message.agentFieldSchemasJson[k]).join(); + /* map agent_instruction_lines = 6; */ + for (let k of globalThis.Object.keys(message.agentInstructionLines)) + writer.tag(6, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k).tag(2, WireType.LengthDelimited).string(message.agentInstructionLines[k]).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.WorkflowTopologyMsg + */ +export const WorkflowTopologyMsg = new WorkflowTopologyMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class FlowInfoMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.FlowInfoMsg", [ + { no: 1, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "file_path", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "node_ids", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "graph", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "message", T: () => NodeEdges } }, + { no: 5, name: "node_types", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } }, + { no: 6, name: "display_names", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } }, + { no: 7, name: "cron", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 8, name: "next_run_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 9, name: "last_run_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 10, name: "workflow_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 11, name: "display_name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 12, name: "root_alias", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 13, name: "relative_file", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 14, name: "builder_symbol", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 15, name: "agent_node_ids", kind: "scalar", repeat: 2 /*RepeatType.UNPACKED*/, T: 9 /*ScalarType.STRING*/ }, + { no: 16, name: "agent_metadata_json", kind: "map", K: 9 /*ScalarType.STRING*/, V: { kind: "scalar", T: 9 /*ScalarType.STRING*/ } }, + { no: 17, name: "webhook_path", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 18, name: "webhook_url", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 19, name: "webhook_active", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): FlowInfoMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.name = ""; + message.filePath = ""; + message.nodeIds = []; + message.graph = {}; + message.nodeTypes = {}; + message.displayNames = {}; + message.cron = ""; + message.nextRunAt = 0; + message.lastRunAt = 0; + message.workflowId = ""; + message.displayName = ""; + message.rootAlias = ""; + message.relativeFile = ""; + message.builderSymbol = ""; + message.agentNodeIds = []; + message.agentMetadataJson = {}; + message.webhookPath = ""; + message.webhookUrl = ""; + message.webhookActive = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: FlowInfoMsg): FlowInfoMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string name */ 1: + message.name = reader.string(); + break; + case /* string file_path */ 2: + message.filePath = reader.string(); + break; + case /* repeated string node_ids */ 3: + message.nodeIds.push(reader.string()); + break; + case /* map graph */ 4: + this.binaryReadMap4(message.graph, reader, options); + break; + case /* map node_types */ 5: + this.binaryReadMap5(message.nodeTypes, reader, options); + break; + case /* map display_names */ 6: + this.binaryReadMap6(message.displayNames, reader, options); + break; + case /* string cron */ 7: + message.cron = reader.string(); + break; + case /* double next_run_at */ 8: + message.nextRunAt = reader.double(); + break; + case /* double last_run_at */ 9: + message.lastRunAt = reader.double(); + break; + case /* string workflow_id */ 10: + message.workflowId = reader.string(); + break; + case /* string display_name */ 11: + message.displayName = reader.string(); + break; + case /* string root_alias */ 12: + message.rootAlias = reader.string(); + break; + case /* string relative_file */ 13: + message.relativeFile = reader.string(); + break; + case /* string builder_symbol */ 14: + message.builderSymbol = reader.string(); + break; + case /* repeated string agent_node_ids */ 15: + message.agentNodeIds.push(reader.string()); + break; + case /* map agent_metadata_json */ 16: + this.binaryReadMap16(message.agentMetadataJson, reader, options); + break; + case /* string webhook_path */ 17: + message.webhookPath = reader.string(); + break; + case /* string webhook_url */ 18: + message.webhookUrl = reader.string(); + break; + case /* bool webhook_active */ 19: + message.webhookActive = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + private binaryReadMap4(map: FlowInfoMsg["graph"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof FlowInfoMsg["graph"] | undefined, val: FlowInfoMsg["graph"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = NodeEdges.internalBinaryRead(reader, reader.uint32(), options); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.FlowInfoMsg.graph"); + } + } + map[key ?? ""] = val ?? NodeEdges.create(); + } + private binaryReadMap5(map: FlowInfoMsg["nodeTypes"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof FlowInfoMsg["nodeTypes"] | undefined, val: FlowInfoMsg["nodeTypes"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = reader.string(); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.FlowInfoMsg.node_types"); + } + } + map[key ?? ""] = val ?? ""; + } + private binaryReadMap6(map: FlowInfoMsg["displayNames"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof FlowInfoMsg["displayNames"] | undefined, val: FlowInfoMsg["displayNames"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = reader.string(); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.FlowInfoMsg.display_names"); + } + } + map[key ?? ""] = val ?? ""; + } + private binaryReadMap16(map: FlowInfoMsg["agentMetadataJson"], reader: IBinaryReader, options: BinaryReadOptions): void { + let len = reader.uint32(), end = reader.pos + len, key: keyof FlowInfoMsg["agentMetadataJson"] | undefined, val: FlowInfoMsg["agentMetadataJson"][any] | undefined; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case 1: + key = reader.string(); + break; + case 2: + val = reader.string(); + break; + default: throw new globalThis.Error("unknown map entry field for avalanche.operator.FlowInfoMsg.agent_metadata_json"); + } + } + map[key ?? ""] = val ?? ""; + } + internalBinaryWrite(message: FlowInfoMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string name = 1; */ + if (message.name !== "") + writer.tag(1, WireType.LengthDelimited).string(message.name); + /* string file_path = 2; */ + if (message.filePath !== "") + writer.tag(2, WireType.LengthDelimited).string(message.filePath); + /* repeated string node_ids = 3; */ + for (let i = 0; i < message.nodeIds.length; i++) + writer.tag(3, WireType.LengthDelimited).string(message.nodeIds[i]); + /* map graph = 4; */ + for (let k of globalThis.Object.keys(message.graph)) { + writer.tag(4, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k); + writer.tag(2, WireType.LengthDelimited).fork(); + NodeEdges.internalBinaryWrite(message.graph[k], writer, options); + writer.join().join(); + } + /* map node_types = 5; */ + for (let k of globalThis.Object.keys(message.nodeTypes)) + writer.tag(5, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k).tag(2, WireType.LengthDelimited).string(message.nodeTypes[k]).join(); + /* map display_names = 6; */ + for (let k of globalThis.Object.keys(message.displayNames)) + writer.tag(6, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k).tag(2, WireType.LengthDelimited).string(message.displayNames[k]).join(); + /* string cron = 7; */ + if (message.cron !== "") + writer.tag(7, WireType.LengthDelimited).string(message.cron); + /* double next_run_at = 8; */ + if (message.nextRunAt !== 0) + writer.tag(8, WireType.Bit64).double(message.nextRunAt); + /* double last_run_at = 9; */ + if (message.lastRunAt !== 0) + writer.tag(9, WireType.Bit64).double(message.lastRunAt); + /* string workflow_id = 10; */ + if (message.workflowId !== "") + writer.tag(10, WireType.LengthDelimited).string(message.workflowId); + /* string display_name = 11; */ + if (message.displayName !== "") + writer.tag(11, WireType.LengthDelimited).string(message.displayName); + /* string root_alias = 12; */ + if (message.rootAlias !== "") + writer.tag(12, WireType.LengthDelimited).string(message.rootAlias); + /* string relative_file = 13; */ + if (message.relativeFile !== "") + writer.tag(13, WireType.LengthDelimited).string(message.relativeFile); + /* string builder_symbol = 14; */ + if (message.builderSymbol !== "") + writer.tag(14, WireType.LengthDelimited).string(message.builderSymbol); + /* repeated string agent_node_ids = 15; */ + for (let i = 0; i < message.agentNodeIds.length; i++) + writer.tag(15, WireType.LengthDelimited).string(message.agentNodeIds[i]); + /* map agent_metadata_json = 16; */ + for (let k of globalThis.Object.keys(message.agentMetadataJson)) + writer.tag(16, WireType.LengthDelimited).fork().tag(1, WireType.LengthDelimited).string(k).tag(2, WireType.LengthDelimited).string(message.agentMetadataJson[k]).join(); + /* string webhook_path = 17; */ + if (message.webhookPath !== "") + writer.tag(17, WireType.LengthDelimited).string(message.webhookPath); + /* string webhook_url = 18; */ + if (message.webhookUrl !== "") + writer.tag(18, WireType.LengthDelimited).string(message.webhookUrl); + /* bool webhook_active = 19; */ + if (message.webhookActive !== false) + writer.tag(19, WireType.Varint).bool(message.webhookActive); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.FlowInfoMsg + */ +export const FlowInfoMsg = new FlowInfoMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DiscoveryDiagnosticMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.DiscoveryDiagnosticMsg", [ + { no: 1, name: "path", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "kind", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "message", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): DiscoveryDiagnosticMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.path = ""; + message.kind = ""; + message.message = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DiscoveryDiagnosticMsg): DiscoveryDiagnosticMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string path */ 1: + message.path = reader.string(); + break; + case /* string kind */ 2: + message.kind = reader.string(); + break; + case /* string message */ 3: + message.message = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DiscoveryDiagnosticMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string path = 1; */ + if (message.path !== "") + writer.tag(1, WireType.LengthDelimited).string(message.path); + /* string kind = 2; */ + if (message.kind !== "") + writer.tag(2, WireType.LengthDelimited).string(message.kind); + /* string message = 3; */ + if (message.message !== "") + writer.tag(3, WireType.LengthDelimited).string(message.message); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.DiscoveryDiagnosticMsg + */ +export const DiscoveryDiagnosticMsg = new DiscoveryDiagnosticMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ScanTargetMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.ScanTargetMsg", [ + { no: 1, name: "alias", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "target_path", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "kind", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ScanTargetMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.alias = ""; + message.targetPath = ""; + message.kind = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ScanTargetMsg): ScanTargetMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string alias */ 1: + message.alias = reader.string(); + break; + case /* string target_path */ 2: + message.targetPath = reader.string(); + break; + case /* string kind */ 3: + message.kind = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ScanTargetMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string alias = 1; */ + if (message.alias !== "") + writer.tag(1, WireType.LengthDelimited).string(message.alias); + /* string target_path = 2; */ + if (message.targetPath !== "") + writer.tag(2, WireType.LengthDelimited).string(message.targetPath); + /* string kind = 3; */ + if (message.kind !== "") + writer.tag(3, WireType.LengthDelimited).string(message.kind); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.ScanTargetMsg + */ +export const ScanTargetMsg = new ScanTargetMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class CatalogSnapshotMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.CatalogSnapshotMsg", [ + { no: 1, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "as_of_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "revision", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 4, name: "workflows", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => FlowInfoMsg }, + { no: 5, name: "scan_targets", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => ScanTargetMsg }, + { no: 6, name: "diagnostics", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => DiscoveryDiagnosticMsg } + ]); + } + create(value?: PartialMessage): CatalogSnapshotMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.operatorInstanceId = ""; + message.asOfSequence = "0"; + message.revision = "0"; + message.workflows = []; + message.scanTargets = []; + message.diagnostics = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CatalogSnapshotMsg): CatalogSnapshotMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string operator_instance_id */ 1: + message.operatorInstanceId = reader.string(); + break; + case /* uint64 as_of_sequence */ 2: + message.asOfSequence = reader.uint64().toString(); + break; + case /* uint64 revision */ 3: + message.revision = reader.uint64().toString(); + break; + case /* repeated avalanche.operator.FlowInfoMsg workflows */ 4: + message.workflows.push(FlowInfoMsg.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* repeated avalanche.operator.ScanTargetMsg scan_targets */ 5: + message.scanTargets.push(ScanTargetMsg.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* repeated avalanche.operator.DiscoveryDiagnosticMsg diagnostics */ 6: + message.diagnostics.push(DiscoveryDiagnosticMsg.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: CatalogSnapshotMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string operator_instance_id = 1; */ + if (message.operatorInstanceId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.operatorInstanceId); + /* uint64 as_of_sequence = 2; */ + if (message.asOfSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.asOfSequence); + /* uint64 revision = 3; */ + if (message.revision !== "0") + writer.tag(3, WireType.Varint).uint64(message.revision); + /* repeated avalanche.operator.FlowInfoMsg workflows = 4; */ + for (let i = 0; i < message.workflows.length; i++) + FlowInfoMsg.internalBinaryWrite(message.workflows[i], writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* repeated avalanche.operator.ScanTargetMsg scan_targets = 5; */ + for (let i = 0; i < message.scanTargets.length; i++) + ScanTargetMsg.internalBinaryWrite(message.scanTargets[i], writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + /* repeated avalanche.operator.DiscoveryDiagnosticMsg diagnostics = 6; */ + for (let i = 0; i < message.diagnostics.length; i++) + DiscoveryDiagnosticMsg.internalBinaryWrite(message.diagnostics[i], writer.tag(6, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.CatalogSnapshotMsg + */ +export const CatalogSnapshotMsg = new CatalogSnapshotMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ResultFileAttachment$Type extends MessageType { + constructor() { + super("avalanche.operator.ResultFileAttachment", [ + { no: 1, name: "attachment_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "content", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 4, name: "media_type", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "sha256", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): ResultFileAttachment { + const message = globalThis.Object.create((this.messagePrototype!)); + message.attachmentId = ""; + message.content = new Uint8Array(0); + message.sha256 = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ResultFileAttachment): ResultFileAttachment { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string attachment_id */ 1: + message.attachmentId = reader.string(); + break; + case /* optional string name */ 2: + message.name = reader.string(); + break; + case /* bytes content */ 3: + message.content = reader.bytes(); + break; + case /* optional string media_type */ 4: + message.mediaType = reader.string(); + break; + case /* string sha256 */ 5: + message.sha256 = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ResultFileAttachment, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string attachment_id = 1; */ + if (message.attachmentId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.attachmentId); + /* optional string name = 2; */ + if (message.name !== undefined) + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* bytes content = 3; */ + if (message.content.length) + writer.tag(3, WireType.LengthDelimited).bytes(message.content); + /* optional string media_type = 4; */ + if (message.mediaType !== undefined) + writer.tag(4, WireType.LengthDelimited).string(message.mediaType); + /* string sha256 = 5; */ + if (message.sha256 !== "") + writer.tag(5, WireType.LengthDelimited).string(message.sha256); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.ResultFileAttachment + */ +export const ResultFileAttachment = new ResultFileAttachment$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RunResultMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.RunResultMsg", [ + { no: 1, name: "value_json", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "files", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => ResultFileAttachment } + ]); + } + create(value?: PartialMessage): RunResultMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.valueJson = ""; + message.files = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RunResultMsg): RunResultMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string value_json */ 1: + message.valueJson = reader.string(); + break; + case /* repeated avalanche.operator.ResultFileAttachment files */ 2: + message.files.push(ResultFileAttachment.internalBinaryRead(reader, reader.uint32(), options)); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RunResultMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string value_json = 1; */ + if (message.valueJson !== "") + writer.tag(1, WireType.LengthDelimited).string(message.valueJson); + /* repeated avalanche.operator.ResultFileAttachment files = 2; */ + for (let i = 0; i < message.files.length; i++) + ResultFileAttachment.internalBinaryWrite(message.files[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.RunResultMsg + */ +export const RunResultMsg = new RunResultMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RunSummaryMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.RunSummaryMsg", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "flow_name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "status", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "started_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 5, name: "ended_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 6, name: "triggered_by", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 7, name: "workflow_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 8, name: "workflow_display_name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 9, name: "created_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 10, name: "revision", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 11, name: "triggered_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ } + ]); + } + create(value?: PartialMessage): RunSummaryMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + message.flowName = ""; + message.status = ""; + message.startedAt = 0; + message.endedAt = 0; + message.triggeredBy = ""; + message.workflowId = ""; + message.workflowDisplayName = ""; + message.createdSequence = "0"; + message.revision = "0"; + message.triggeredAt = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RunSummaryMsg): RunSummaryMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* string flow_name */ 2: + message.flowName = reader.string(); + break; + case /* string status */ 3: + message.status = reader.string(); + break; + case /* double started_at */ 4: + message.startedAt = reader.double(); + break; + case /* double ended_at */ 5: + message.endedAt = reader.double(); + break; + case /* string triggered_by */ 6: + message.triggeredBy = reader.string(); + break; + case /* string workflow_id */ 7: + message.workflowId = reader.string(); + break; + case /* string workflow_display_name */ 8: + message.workflowDisplayName = reader.string(); + break; + case /* uint64 created_sequence */ 9: + message.createdSequence = reader.uint64().toString(); + break; + case /* uint64 revision */ 10: + message.revision = reader.uint64().toString(); + break; + case /* double triggered_at */ 11: + message.triggeredAt = reader.double(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RunSummaryMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* string flow_name = 2; */ + if (message.flowName !== "") + writer.tag(2, WireType.LengthDelimited).string(message.flowName); + /* string status = 3; */ + if (message.status !== "") + writer.tag(3, WireType.LengthDelimited).string(message.status); + /* double started_at = 4; */ + if (message.startedAt !== 0) + writer.tag(4, WireType.Bit64).double(message.startedAt); + /* double ended_at = 5; */ + if (message.endedAt !== 0) + writer.tag(5, WireType.Bit64).double(message.endedAt); + /* string triggered_by = 6; */ + if (message.triggeredBy !== "") + writer.tag(6, WireType.LengthDelimited).string(message.triggeredBy); + /* string workflow_id = 7; */ + if (message.workflowId !== "") + writer.tag(7, WireType.LengthDelimited).string(message.workflowId); + /* string workflow_display_name = 8; */ + if (message.workflowDisplayName !== "") + writer.tag(8, WireType.LengthDelimited).string(message.workflowDisplayName); + /* uint64 created_sequence = 9; */ + if (message.createdSequence !== "0") + writer.tag(9, WireType.Varint).uint64(message.createdSequence); + /* uint64 revision = 10; */ + if (message.revision !== "0") + writer.tag(10, WireType.Varint).uint64(message.revision); + /* double triggered_at = 11; */ + if (message.triggeredAt !== 0) + writer.tag(11, WireType.Bit64).double(message.triggeredAt); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.RunSummaryMsg + */ +export const RunSummaryMsg = new RunSummaryMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TraceHeaderMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.TraceHeaderMsg", [ + { no: 1, name: "status", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "model", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "sub_model", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "iterations", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 5, name: "max_iterations", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 6, name: "duration_ms", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 7, name: "usage_json", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 8, name: "telemetry_json", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): TraceHeaderMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.status = ""; + message.model = ""; + message.iterations = "0"; + message.maxIterations = "0"; + message.durationMs = "0"; + message.usageJson = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TraceHeaderMsg): TraceHeaderMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string status */ 1: + message.status = reader.string(); + break; + case /* string model */ 2: + message.model = reader.string(); + break; + case /* optional string sub_model */ 3: + message.subModel = reader.string(); + break; + case /* uint64 iterations */ 4: + message.iterations = reader.uint64().toString(); + break; + case /* uint64 max_iterations */ 5: + message.maxIterations = reader.uint64().toString(); + break; + case /* uint64 duration_ms */ 6: + message.durationMs = reader.uint64().toString(); + break; + case /* string usage_json */ 7: + message.usageJson = reader.string(); + break; + case /* optional string telemetry_json */ 8: + message.telemetryJson = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TraceHeaderMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string status = 1; */ + if (message.status !== "") + writer.tag(1, WireType.LengthDelimited).string(message.status); + /* string model = 2; */ + if (message.model !== "") + writer.tag(2, WireType.LengthDelimited).string(message.model); + /* optional string sub_model = 3; */ + if (message.subModel !== undefined) + writer.tag(3, WireType.LengthDelimited).string(message.subModel); + /* uint64 iterations = 4; */ + if (message.iterations !== "0") + writer.tag(4, WireType.Varint).uint64(message.iterations); + /* uint64 max_iterations = 5; */ + if (message.maxIterations !== "0") + writer.tag(5, WireType.Varint).uint64(message.maxIterations); + /* uint64 duration_ms = 6; */ + if (message.durationMs !== "0") + writer.tag(6, WireType.Varint).uint64(message.durationMs); + /* string usage_json = 7; */ + if (message.usageJson !== "") + writer.tag(7, WireType.LengthDelimited).string(message.usageJson); + /* optional string telemetry_json = 8; */ + if (message.telemetryJson !== undefined) + writer.tag(8, WireType.LengthDelimited).string(message.telemetryJson); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.TraceHeaderMsg + */ +export const TraceHeaderMsg = new TraceHeaderMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TraceDescriptorMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.TraceDescriptorMsg", [ + { no: 1, name: "status", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "revision", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "available", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 4, name: "complete", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 5, name: "event_count", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 6, name: "size_bytes", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 7, name: "latest_event_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 8, name: "header", kind: "message", T: () => TraceHeaderMsg } + ]); + } + create(value?: PartialMessage): TraceDescriptorMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.status = ""; + message.revision = "0"; + message.available = false; + message.complete = false; + message.eventCount = "0"; + message.sizeBytes = "0"; + message.latestEventSequence = "0"; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TraceDescriptorMsg): TraceDescriptorMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string status */ 1: + message.status = reader.string(); + break; + case /* uint64 revision */ 2: + message.revision = reader.uint64().toString(); + break; + case /* bool available */ 3: + message.available = reader.bool(); + break; + case /* bool complete */ 4: + message.complete = reader.bool(); + break; + case /* uint64 event_count */ 5: + message.eventCount = reader.uint64().toString(); + break; + case /* uint64 size_bytes */ 6: + message.sizeBytes = reader.uint64().toString(); + break; + case /* uint64 latest_event_sequence */ 7: + message.latestEventSequence = reader.uint64().toString(); + break; + case /* avalanche.operator.TraceHeaderMsg header */ 8: + message.header = TraceHeaderMsg.internalBinaryRead(reader, reader.uint32(), options, message.header); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TraceDescriptorMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string status = 1; */ + if (message.status !== "") + writer.tag(1, WireType.LengthDelimited).string(message.status); + /* uint64 revision = 2; */ + if (message.revision !== "0") + writer.tag(2, WireType.Varint).uint64(message.revision); + /* bool available = 3; */ + if (message.available !== false) + writer.tag(3, WireType.Varint).bool(message.available); + /* bool complete = 4; */ + if (message.complete !== false) + writer.tag(4, WireType.Varint).bool(message.complete); + /* uint64 event_count = 5; */ + if (message.eventCount !== "0") + writer.tag(5, WireType.Varint).uint64(message.eventCount); + /* uint64 size_bytes = 6; */ + if (message.sizeBytes !== "0") + writer.tag(6, WireType.Varint).uint64(message.sizeBytes); + /* uint64 latest_event_sequence = 7; */ + if (message.latestEventSequence !== "0") + writer.tag(7, WireType.Varint).uint64(message.latestEventSequence); + /* avalanche.operator.TraceHeaderMsg header = 8; */ + if (message.header) + TraceHeaderMsg.internalBinaryWrite(message.header, writer.tag(8, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.TraceDescriptorMsg + */ +export const TraceDescriptorMsg = new TraceDescriptorMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class NodeSnapshotMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.NodeSnapshotMsg", [ + { no: 1, name: "node_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "name", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "node_type", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "status", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "started_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 6, name: "ended_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 7, name: "trace", kind: "message", T: () => TraceDescriptorMsg }, + { no: 8, name: "revision", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 9, name: "event_page_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 10, name: "error", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 11, name: "running_elapsed_seconds", kind: "scalar", opt: true, T: 1 /*ScalarType.DOUBLE*/ } + ]); + } + create(value?: PartialMessage): NodeSnapshotMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.nodeId = ""; + message.name = ""; + message.nodeType = ""; + message.status = ""; + message.startedAt = 0; + message.endedAt = 0; + message.revision = "0"; + message.eventPageToken = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: NodeSnapshotMsg): NodeSnapshotMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string node_id */ 1: + message.nodeId = reader.string(); + break; + case /* string name */ 2: + message.name = reader.string(); + break; + case /* string node_type */ 3: + message.nodeType = reader.string(); + break; + case /* string status */ 4: + message.status = reader.string(); + break; + case /* double started_at */ 5: + message.startedAt = reader.double(); + break; + case /* double ended_at */ 6: + message.endedAt = reader.double(); + break; + case /* avalanche.operator.TraceDescriptorMsg trace */ 7: + message.trace = TraceDescriptorMsg.internalBinaryRead(reader, reader.uint32(), options, message.trace); + break; + case /* uint64 revision */ 8: + message.revision = reader.uint64().toString(); + break; + case /* string event_page_token */ 9: + message.eventPageToken = reader.string(); + break; + case /* optional string error */ 10: + message.error = reader.string(); + break; + case /* optional double running_elapsed_seconds */ 11: + message.runningElapsedSeconds = reader.double(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: NodeSnapshotMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string node_id = 1; */ + if (message.nodeId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.nodeId); + /* string name = 2; */ + if (message.name !== "") + writer.tag(2, WireType.LengthDelimited).string(message.name); + /* string node_type = 3; */ + if (message.nodeType !== "") + writer.tag(3, WireType.LengthDelimited).string(message.nodeType); + /* string status = 4; */ + if (message.status !== "") + writer.tag(4, WireType.LengthDelimited).string(message.status); + /* double started_at = 5; */ + if (message.startedAt !== 0) + writer.tag(5, WireType.Bit64).double(message.startedAt); + /* double ended_at = 6; */ + if (message.endedAt !== 0) + writer.tag(6, WireType.Bit64).double(message.endedAt); + /* avalanche.operator.TraceDescriptorMsg trace = 7; */ + if (message.trace) + TraceDescriptorMsg.internalBinaryWrite(message.trace, writer.tag(7, WireType.LengthDelimited).fork(), options).join(); + /* uint64 revision = 8; */ + if (message.revision !== "0") + writer.tag(8, WireType.Varint).uint64(message.revision); + /* string event_page_token = 9; */ + if (message.eventPageToken !== "") + writer.tag(9, WireType.LengthDelimited).string(message.eventPageToken); + /* optional string error = 10; */ + if (message.error !== undefined) + writer.tag(10, WireType.LengthDelimited).string(message.error); + /* optional double running_elapsed_seconds = 11; */ + if (message.runningElapsedSeconds !== undefined) + writer.tag(11, WireType.Bit64).double(message.runningElapsedSeconds); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.NodeSnapshotMsg + */ +export const NodeSnapshotMsg = new NodeSnapshotMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RunSnapshotMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.RunSnapshotMsg", [ + { no: 1, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "as_of_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "summary", kind: "message", T: () => RunSummaryMsg }, + { no: 4, name: "nodes", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => NodeSnapshotMsg }, + { no: 5, name: "latest_log_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 6, name: "log_page_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 7, name: "topology", kind: "message", T: () => WorkflowTopologyMsg } + ]); + } + create(value?: PartialMessage): RunSnapshotMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.operatorInstanceId = ""; + message.asOfSequence = "0"; + message.nodes = []; + message.latestLogSequence = "0"; + message.logPageToken = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RunSnapshotMsg): RunSnapshotMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string operator_instance_id */ 1: + message.operatorInstanceId = reader.string(); + break; + case /* uint64 as_of_sequence */ 2: + message.asOfSequence = reader.uint64().toString(); + break; + case /* avalanche.operator.RunSummaryMsg summary */ 3: + message.summary = RunSummaryMsg.internalBinaryRead(reader, reader.uint32(), options, message.summary); + break; + case /* repeated avalanche.operator.NodeSnapshotMsg nodes */ 4: + message.nodes.push(NodeSnapshotMsg.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* uint64 latest_log_sequence */ 5: + message.latestLogSequence = reader.uint64().toString(); + break; + case /* string log_page_token */ 6: + message.logPageToken = reader.string(); + break; + case /* avalanche.operator.WorkflowTopologyMsg topology */ 7: + message.topology = WorkflowTopologyMsg.internalBinaryRead(reader, reader.uint32(), options, message.topology); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RunSnapshotMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string operator_instance_id = 1; */ + if (message.operatorInstanceId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.operatorInstanceId); + /* uint64 as_of_sequence = 2; */ + if (message.asOfSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.asOfSequence); + /* avalanche.operator.RunSummaryMsg summary = 3; */ + if (message.summary) + RunSummaryMsg.internalBinaryWrite(message.summary, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* repeated avalanche.operator.NodeSnapshotMsg nodes = 4; */ + for (let i = 0; i < message.nodes.length; i++) + NodeSnapshotMsg.internalBinaryWrite(message.nodes[i], writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* uint64 latest_log_sequence = 5; */ + if (message.latestLogSequence !== "0") + writer.tag(5, WireType.Varint).uint64(message.latestLogSequence); + /* string log_page_token = 6; */ + if (message.logPageToken !== "") + writer.tag(6, WireType.LengthDelimited).string(message.logPageToken); + /* avalanche.operator.WorkflowTopologyMsg topology = 7; */ + if (message.topology) + WorkflowTopologyMsg.internalBinaryWrite(message.topology, writer.tag(7, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.RunSnapshotMsg + */ +export const RunSnapshotMsg = new RunSnapshotMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RunSummaryPage$Type extends MessageType { + constructor() { + super("avalanche.operator.RunSummaryPage", [ + { no: 1, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "as_of_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "runs", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => RunSummaryMsg }, + { no: 4, name: "next_page_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): RunSummaryPage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.operatorInstanceId = ""; + message.asOfSequence = "0"; + message.runs = []; + message.nextPageToken = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RunSummaryPage): RunSummaryPage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string operator_instance_id */ 1: + message.operatorInstanceId = reader.string(); + break; + case /* uint64 as_of_sequence */ 2: + message.asOfSequence = reader.uint64().toString(); + break; + case /* repeated avalanche.operator.RunSummaryMsg runs */ 3: + message.runs.push(RunSummaryMsg.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* string next_page_token */ 4: + message.nextPageToken = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RunSummaryPage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string operator_instance_id = 1; */ + if (message.operatorInstanceId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.operatorInstanceId); + /* uint64 as_of_sequence = 2; */ + if (message.asOfSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.asOfSequence); + /* repeated avalanche.operator.RunSummaryMsg runs = 3; */ + for (let i = 0; i < message.runs.length; i++) + RunSummaryMsg.internalBinaryWrite(message.runs[i], writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* string next_page_token = 4; */ + if (message.nextPageToken !== "") + writer.tag(4, WireType.LengthDelimited).string(message.nextPageToken); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.RunSummaryPage + */ +export const RunSummaryPage = new RunSummaryPage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LogRecordDescriptorMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.LogRecordDescriptorMsg", [ + { no: 1, name: "sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 2, name: "timestamp", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 3, name: "level", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "node_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "size_bytes", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 6, name: "body_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): LogRecordDescriptorMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.sequence = "0"; + message.timestamp = 0; + message.level = ""; + message.nodeId = ""; + message.sizeBytes = "0"; + message.bodyToken = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LogRecordDescriptorMsg): LogRecordDescriptorMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint64 sequence */ 1: + message.sequence = reader.uint64().toString(); + break; + case /* double timestamp */ 2: + message.timestamp = reader.double(); + break; + case /* string level */ 3: + message.level = reader.string(); + break; + case /* string node_id */ 4: + message.nodeId = reader.string(); + break; + case /* uint64 size_bytes */ 5: + message.sizeBytes = reader.uint64().toString(); + break; + case /* string body_token */ 6: + message.bodyToken = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LogRecordDescriptorMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint64 sequence = 1; */ + if (message.sequence !== "0") + writer.tag(1, WireType.Varint).uint64(message.sequence); + /* double timestamp = 2; */ + if (message.timestamp !== 0) + writer.tag(2, WireType.Bit64).double(message.timestamp); + /* string level = 3; */ + if (message.level !== "") + writer.tag(3, WireType.LengthDelimited).string(message.level); + /* string node_id = 4; */ + if (message.nodeId !== "") + writer.tag(4, WireType.LengthDelimited).string(message.nodeId); + /* uint64 size_bytes = 5; */ + if (message.sizeBytes !== "0") + writer.tag(5, WireType.Varint).uint64(message.sizeBytes); + /* string body_token = 6; */ + if (message.bodyToken !== "") + writer.tag(6, WireType.LengthDelimited).string(message.bodyToken); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.LogRecordDescriptorMsg + */ +export const LogRecordDescriptorMsg = new LogRecordDescriptorMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LogPage$Type extends MessageType { + constructor() { + super("avalanche.operator.LogPage", [ + { no: 1, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "as_of_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "logs", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => LogRecordDescriptorMsg }, + { no: 4, name: "next_page_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): LogPage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.operatorInstanceId = ""; + message.asOfSequence = "0"; + message.logs = []; + message.nextPageToken = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LogPage): LogPage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string operator_instance_id */ 1: + message.operatorInstanceId = reader.string(); + break; + case /* uint64 as_of_sequence */ 2: + message.asOfSequence = reader.uint64().toString(); + break; + case /* repeated avalanche.operator.LogRecordDescriptorMsg logs */ 3: + message.logs.push(LogRecordDescriptorMsg.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* string next_page_token */ 4: + message.nextPageToken = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LogPage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string operator_instance_id = 1; */ + if (message.operatorInstanceId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.operatorInstanceId); + /* uint64 as_of_sequence = 2; */ + if (message.asOfSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.asOfSequence); + /* repeated avalanche.operator.LogRecordDescriptorMsg logs = 3; */ + for (let i = 0; i < message.logs.length; i++) + LogRecordDescriptorMsg.internalBinaryWrite(message.logs[i], writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* string next_page_token = 4; */ + if (message.nextPageToken !== "") + writer.tag(4, WireType.LengthDelimited).string(message.nextPageToken); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.LogPage + */ +export const LogPage = new LogPage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AgentEventDescriptorMsg$Type extends MessageType { + constructor() { + super("avalanche.operator.AgentEventDescriptorMsg", [ + { no: 1, name: "event_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 2, name: "size_bytes", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "body_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "invocation_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "event_kind", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 6, name: "iteration", kind: "scalar", opt: true, T: 13 /*ScalarType.UINT32*/ }, + { no: 7, name: "duration_ms", kind: "scalar", opt: true, T: 4 /*ScalarType.UINT64*/ }, + { no: 8, name: "error", kind: "scalar", T: 8 /*ScalarType.BOOL*/ }, + { no: 9, name: "tool_count", kind: "scalar", T: 13 /*ScalarType.UINT32*/ }, + { no: 10, name: "predict_count", kind: "scalar", T: 13 /*ScalarType.UINT32*/ } + ]); + } + create(value?: PartialMessage): AgentEventDescriptorMsg { + const message = globalThis.Object.create((this.messagePrototype!)); + message.eventSequence = "0"; + message.sizeBytes = "0"; + message.bodyToken = ""; + message.invocationId = ""; + message.eventKind = ""; + message.error = false; + message.toolCount = 0; + message.predictCount = 0; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AgentEventDescriptorMsg): AgentEventDescriptorMsg { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint64 event_sequence */ 1: + message.eventSequence = reader.uint64().toString(); + break; + case /* uint64 size_bytes */ 2: + message.sizeBytes = reader.uint64().toString(); + break; + case /* string body_token */ 3: + message.bodyToken = reader.string(); + break; + case /* string invocation_id */ 4: + message.invocationId = reader.string(); + break; + case /* string event_kind */ 5: + message.eventKind = reader.string(); + break; + case /* optional uint32 iteration */ 6: + message.iteration = reader.uint32(); + break; + case /* optional uint64 duration_ms */ 7: + message.durationMs = reader.uint64().toString(); + break; + case /* bool error */ 8: + message.error = reader.bool(); + break; + case /* uint32 tool_count */ 9: + message.toolCount = reader.uint32(); + break; + case /* uint32 predict_count */ 10: + message.predictCount = reader.uint32(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AgentEventDescriptorMsg, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint64 event_sequence = 1; */ + if (message.eventSequence !== "0") + writer.tag(1, WireType.Varint).uint64(message.eventSequence); + /* uint64 size_bytes = 2; */ + if (message.sizeBytes !== "0") + writer.tag(2, WireType.Varint).uint64(message.sizeBytes); + /* string body_token = 3; */ + if (message.bodyToken !== "") + writer.tag(3, WireType.LengthDelimited).string(message.bodyToken); + /* string invocation_id = 4; */ + if (message.invocationId !== "") + writer.tag(4, WireType.LengthDelimited).string(message.invocationId); + /* string event_kind = 5; */ + if (message.eventKind !== "") + writer.tag(5, WireType.LengthDelimited).string(message.eventKind); + /* optional uint32 iteration = 6; */ + if (message.iteration !== undefined) + writer.tag(6, WireType.Varint).uint32(message.iteration); + /* optional uint64 duration_ms = 7; */ + if (message.durationMs !== undefined) + writer.tag(7, WireType.Varint).uint64(message.durationMs); + /* bool error = 8; */ + if (message.error !== false) + writer.tag(8, WireType.Varint).bool(message.error); + /* uint32 tool_count = 9; */ + if (message.toolCount !== 0) + writer.tag(9, WireType.Varint).uint32(message.toolCount); + /* uint32 predict_count = 10; */ + if (message.predictCount !== 0) + writer.tag(10, WireType.Varint).uint32(message.predictCount); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.AgentEventDescriptorMsg + */ +export const AgentEventDescriptorMsg = new AgentEventDescriptorMsg$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AgentEventPage$Type extends MessageType { + constructor() { + super("avalanche.operator.AgentEventPage", [ + { no: 1, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "as_of_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "node_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 5, name: "events", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => AgentEventDescriptorMsg }, + { no: 6, name: "next_page_token", kind: "scalar", T: 9 /*ScalarType.STRING*/ } + ]); + } + create(value?: PartialMessage): AgentEventPage { + const message = globalThis.Object.create((this.messagePrototype!)); + message.operatorInstanceId = ""; + message.asOfSequence = "0"; + message.runId = ""; + message.nodeId = ""; + message.events = []; + message.nextPageToken = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AgentEventPage): AgentEventPage { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string operator_instance_id */ 1: + message.operatorInstanceId = reader.string(); + break; + case /* uint64 as_of_sequence */ 2: + message.asOfSequence = reader.uint64().toString(); + break; + case /* string run_id */ 3: + message.runId = reader.string(); + break; + case /* string node_id */ 4: + message.nodeId = reader.string(); + break; + case /* repeated avalanche.operator.AgentEventDescriptorMsg events */ 5: + message.events.push(AgentEventDescriptorMsg.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* string next_page_token */ 6: + message.nextPageToken = reader.string(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AgentEventPage, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string operator_instance_id = 1; */ + if (message.operatorInstanceId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.operatorInstanceId); + /* uint64 as_of_sequence = 2; */ + if (message.asOfSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.asOfSequence); + /* string run_id = 3; */ + if (message.runId !== "") + writer.tag(3, WireType.LengthDelimited).string(message.runId); + /* string node_id = 4; */ + if (message.nodeId !== "") + writer.tag(4, WireType.LengthDelimited).string(message.nodeId); + /* repeated avalanche.operator.AgentEventDescriptorMsg events = 5; */ + for (let i = 0; i < message.events.length; i++) + AgentEventDescriptorMsg.internalBinaryWrite(message.events[i], writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + /* string next_page_token = 6; */ + if (message.nextPageToken !== "") + writer.tag(6, WireType.LengthDelimited).string(message.nextPageToken); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.AgentEventPage + */ +export const AgentEventPage = new AgentEventPage$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TraceChunk$Type extends MessageType { + constructor() { + super("avalanche.operator.TraceChunk", [ + { no: 1, name: "revision", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 2, name: "chunk_index", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 3, name: "data", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 4, name: "eof", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): TraceChunk { + const message = globalThis.Object.create((this.messagePrototype!)); + message.revision = "0"; + message.chunkIndex = "0"; + message.data = new Uint8Array(0); + message.eof = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TraceChunk): TraceChunk { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint64 revision */ 1: + message.revision = reader.uint64().toString(); + break; + case /* uint64 chunk_index */ 2: + message.chunkIndex = reader.uint64().toString(); + break; + case /* bytes data */ 3: + message.data = reader.bytes(); + break; + case /* bool eof */ 4: + message.eof = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TraceChunk, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint64 revision = 1; */ + if (message.revision !== "0") + writer.tag(1, WireType.Varint).uint64(message.revision); + /* uint64 chunk_index = 2; */ + if (message.chunkIndex !== "0") + writer.tag(2, WireType.Varint).uint64(message.chunkIndex); + /* bytes data = 3; */ + if (message.data.length) + writer.tag(3, WireType.LengthDelimited).bytes(message.data); + /* bool eof = 4; */ + if (message.eof !== false) + writer.tag(4, WireType.Varint).bool(message.eof); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.TraceChunk + */ +export const TraceChunk = new TraceChunk$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class DetailChunk$Type extends MessageType { + constructor() { + super("avalanche.operator.DetailChunk", [ + { no: 1, name: "chunk_index", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 2, name: "data", kind: "scalar", T: 12 /*ScalarType.BYTES*/ }, + { no: 3, name: "eof", kind: "scalar", T: 8 /*ScalarType.BOOL*/ } + ]); + } + create(value?: PartialMessage): DetailChunk { + const message = globalThis.Object.create((this.messagePrototype!)); + message.chunkIndex = "0"; + message.data = new Uint8Array(0); + message.eof = false; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: DetailChunk): DetailChunk { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint64 chunk_index */ 1: + message.chunkIndex = reader.uint64().toString(); + break; + case /* bytes data */ 2: + message.data = reader.bytes(); + break; + case /* bool eof */ 3: + message.eof = reader.bool(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: DetailChunk, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint64 chunk_index = 1; */ + if (message.chunkIndex !== "0") + writer.tag(1, WireType.Varint).uint64(message.chunkIndex); + /* bytes data = 2; */ + if (message.data.length) + writer.tag(2, WireType.LengthDelimited).bytes(message.data); + /* bool eof = 3; */ + if (message.eof !== false) + writer.tag(3, WireType.Varint).bool(message.eof); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.DetailChunk + */ +export const DetailChunk = new DetailChunk$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RunCreated$Type extends MessageType { + constructor() { + super("avalanche.operator.RunCreated", [ + { no: 1, name: "summary", kind: "message", T: () => RunSummaryMsg }, + { no: 2, name: "nodes", kind: "message", repeat: 2 /*RepeatType.UNPACKED*/, T: () => NodeSnapshotMsg }, + { no: 3, name: "topology", kind: "message", T: () => WorkflowTopologyMsg } + ]); + } + create(value?: PartialMessage): RunCreated { + const message = globalThis.Object.create((this.messagePrototype!)); + message.nodes = []; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RunCreated): RunCreated { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* avalanche.operator.RunSummaryMsg summary */ 1: + message.summary = RunSummaryMsg.internalBinaryRead(reader, reader.uint32(), options, message.summary); + break; + case /* repeated avalanche.operator.NodeSnapshotMsg nodes */ 2: + message.nodes.push(NodeSnapshotMsg.internalBinaryRead(reader, reader.uint32(), options)); + break; + case /* avalanche.operator.WorkflowTopologyMsg topology */ 3: + message.topology = WorkflowTopologyMsg.internalBinaryRead(reader, reader.uint32(), options, message.topology); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RunCreated, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* avalanche.operator.RunSummaryMsg summary = 1; */ + if (message.summary) + RunSummaryMsg.internalBinaryWrite(message.summary, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + /* repeated avalanche.operator.NodeSnapshotMsg nodes = 2; */ + for (let i = 0; i < message.nodes.length; i++) + NodeSnapshotMsg.internalBinaryWrite(message.nodes[i], writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + /* avalanche.operator.WorkflowTopologyMsg topology = 3; */ + if (message.topology) + WorkflowTopologyMsg.internalBinaryWrite(message.topology, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.RunCreated + */ +export const RunCreated = new RunCreated$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class RunStatusChanged$Type extends MessageType { + constructor() { + super("avalanche.operator.RunStatusChanged", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "status", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "started_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 4, name: "ended_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 5, name: "revision", kind: "scalar", T: 4 /*ScalarType.UINT64*/ } + ]); + } + create(value?: PartialMessage): RunStatusChanged { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + message.status = ""; + message.startedAt = 0; + message.endedAt = 0; + message.revision = "0"; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: RunStatusChanged): RunStatusChanged { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* string status */ 2: + message.status = reader.string(); + break; + case /* double started_at */ 3: + message.startedAt = reader.double(); + break; + case /* double ended_at */ 4: + message.endedAt = reader.double(); + break; + case /* uint64 revision */ 5: + message.revision = reader.uint64().toString(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: RunStatusChanged, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* string status = 2; */ + if (message.status !== "") + writer.tag(2, WireType.LengthDelimited).string(message.status); + /* double started_at = 3; */ + if (message.startedAt !== 0) + writer.tag(3, WireType.Bit64).double(message.startedAt); + /* double ended_at = 4; */ + if (message.endedAt !== 0) + writer.tag(4, WireType.Bit64).double(message.endedAt); + /* uint64 revision = 5; */ + if (message.revision !== "0") + writer.tag(5, WireType.Varint).uint64(message.revision); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.RunStatusChanged + */ +export const RunStatusChanged = new RunStatusChanged$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class NodeStatusChanged$Type extends MessageType { + constructor() { + super("avalanche.operator.NodeStatusChanged", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "node_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "status", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 4, name: "started_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 5, name: "ended_at", kind: "scalar", T: 1 /*ScalarType.DOUBLE*/ }, + { no: 6, name: "revision", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 7, name: "error", kind: "scalar", opt: true, T: 9 /*ScalarType.STRING*/ }, + { no: 8, name: "running_elapsed_seconds", kind: "scalar", opt: true, T: 1 /*ScalarType.DOUBLE*/ } + ]); + } + create(value?: PartialMessage): NodeStatusChanged { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + message.nodeId = ""; + message.status = ""; + message.startedAt = 0; + message.endedAt = 0; + message.revision = "0"; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: NodeStatusChanged): NodeStatusChanged { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* string node_id */ 2: + message.nodeId = reader.string(); + break; + case /* string status */ 3: + message.status = reader.string(); + break; + case /* double started_at */ 4: + message.startedAt = reader.double(); + break; + case /* double ended_at */ 5: + message.endedAt = reader.double(); + break; + case /* uint64 revision */ 6: + message.revision = reader.uint64().toString(); + break; + case /* optional string error */ 7: + message.error = reader.string(); + break; + case /* optional double running_elapsed_seconds */ 8: + message.runningElapsedSeconds = reader.double(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: NodeStatusChanged, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* string node_id = 2; */ + if (message.nodeId !== "") + writer.tag(2, WireType.LengthDelimited).string(message.nodeId); + /* string status = 3; */ + if (message.status !== "") + writer.tag(3, WireType.LengthDelimited).string(message.status); + /* double started_at = 4; */ + if (message.startedAt !== 0) + writer.tag(4, WireType.Bit64).double(message.startedAt); + /* double ended_at = 5; */ + if (message.endedAt !== 0) + writer.tag(5, WireType.Bit64).double(message.endedAt); + /* uint64 revision = 6; */ + if (message.revision !== "0") + writer.tag(6, WireType.Varint).uint64(message.revision); + /* optional string error = 7; */ + if (message.error !== undefined) + writer.tag(7, WireType.LengthDelimited).string(message.error); + /* optional double running_elapsed_seconds = 8; */ + if (message.runningElapsedSeconds !== undefined) + writer.tag(8, WireType.Bit64).double(message.runningElapsedSeconds); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.NodeStatusChanged + */ +export const NodeStatusChanged = new NodeStatusChanged$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class LogAppended$Type extends MessageType { + constructor() { + super("avalanche.operator.LogAppended", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "log", kind: "message", T: () => LogRecordDescriptorMsg } + ]); + } + create(value?: PartialMessage): LogAppended { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: LogAppended): LogAppended { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* avalanche.operator.LogRecordDescriptorMsg log */ 2: + message.log = LogRecordDescriptorMsg.internalBinaryRead(reader, reader.uint32(), options, message.log); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: LogAppended, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* avalanche.operator.LogRecordDescriptorMsg log = 2; */ + if (message.log) + LogRecordDescriptorMsg.internalBinaryWrite(message.log, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.LogAppended + */ +export const LogAppended = new LogAppended$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class AgentEventAppended$Type extends MessageType { + constructor() { + super("avalanche.operator.AgentEventAppended", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "node_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "event", kind: "message", T: () => AgentEventDescriptorMsg } + ]); + } + create(value?: PartialMessage): AgentEventAppended { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + message.nodeId = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: AgentEventAppended): AgentEventAppended { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* string node_id */ 2: + message.nodeId = reader.string(); + break; + case /* avalanche.operator.AgentEventDescriptorMsg event */ 3: + message.event = AgentEventDescriptorMsg.internalBinaryRead(reader, reader.uint32(), options, message.event); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: AgentEventAppended, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* string node_id = 2; */ + if (message.nodeId !== "") + writer.tag(2, WireType.LengthDelimited).string(message.nodeId); + /* avalanche.operator.AgentEventDescriptorMsg event = 3; */ + if (message.event) + AgentEventDescriptorMsg.internalBinaryWrite(message.event, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.AgentEventAppended + */ +export const AgentEventAppended = new AgentEventAppended$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class TraceFinalized$Type extends MessageType { + constructor() { + super("avalanche.operator.TraceFinalized", [ + { no: 1, name: "run_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "node_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 3, name: "trace", kind: "message", T: () => TraceDescriptorMsg } + ]); + } + create(value?: PartialMessage): TraceFinalized { + const message = globalThis.Object.create((this.messagePrototype!)); + message.runId = ""; + message.nodeId = ""; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: TraceFinalized): TraceFinalized { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string run_id */ 1: + message.runId = reader.string(); + break; + case /* string node_id */ 2: + message.nodeId = reader.string(); + break; + case /* avalanche.operator.TraceDescriptorMsg trace */ 3: + message.trace = TraceDescriptorMsg.internalBinaryRead(reader, reader.uint32(), options, message.trace); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: TraceFinalized, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string run_id = 1; */ + if (message.runId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.runId); + /* string node_id = 2; */ + if (message.nodeId !== "") + writer.tag(2, WireType.LengthDelimited).string(message.nodeId); + /* avalanche.operator.TraceDescriptorMsg trace = 3; */ + if (message.trace) + TraceDescriptorMsg.internalBinaryWrite(message.trace, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.TraceFinalized + */ +export const TraceFinalized = new TraceFinalized$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class CatalogReplaced$Type extends MessageType { + constructor() { + super("avalanche.operator.CatalogReplaced", [ + { no: 1, name: "catalog", kind: "message", T: () => CatalogSnapshotMsg } + ]); + } + create(value?: PartialMessage): CatalogReplaced { + const message = globalThis.Object.create((this.messagePrototype!)); + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: CatalogReplaced): CatalogReplaced { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* avalanche.operator.CatalogSnapshotMsg catalog */ 1: + message.catalog = CatalogSnapshotMsg.internalBinaryRead(reader, reader.uint32(), options, message.catalog); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: CatalogReplaced, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* avalanche.operator.CatalogSnapshotMsg catalog = 1; */ + if (message.catalog) + CatalogSnapshotMsg.internalBinaryWrite(message.catalog, writer.tag(1, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.CatalogReplaced + */ +export const CatalogReplaced = new CatalogReplaced$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class OperatorUpdate$Type extends MessageType { + constructor() { + super("avalanche.operator.OperatorUpdate", [ + { no: 1, name: "sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 2, name: "run_created", kind: "message", oneof: "change", T: () => RunCreated }, + { no: 3, name: "run_status_changed", kind: "message", oneof: "change", T: () => RunStatusChanged }, + { no: 4, name: "node_status_changed", kind: "message", oneof: "change", T: () => NodeStatusChanged }, + { no: 5, name: "log_appended", kind: "message", oneof: "change", T: () => LogAppended }, + { no: 6, name: "agent_event_appended", kind: "message", oneof: "change", T: () => AgentEventAppended }, + { no: 7, name: "trace_finalized", kind: "message", oneof: "change", T: () => TraceFinalized }, + { no: 8, name: "catalog_replaced", kind: "message", oneof: "change", T: () => CatalogReplaced } + ]); + } + create(value?: PartialMessage): OperatorUpdate { + const message = globalThis.Object.create((this.messagePrototype!)); + message.sequence = "0"; + message.change = { oneofKind: undefined }; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: OperatorUpdate): OperatorUpdate { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint64 sequence */ 1: + message.sequence = reader.uint64().toString(); + break; + case /* avalanche.operator.RunCreated run_created */ 2: + message.change = { + oneofKind: "runCreated", + runCreated: RunCreated.internalBinaryRead(reader, reader.uint32(), options, (message.change as any).runCreated) + }; + break; + case /* avalanche.operator.RunStatusChanged run_status_changed */ 3: + message.change = { + oneofKind: "runStatusChanged", + runStatusChanged: RunStatusChanged.internalBinaryRead(reader, reader.uint32(), options, (message.change as any).runStatusChanged) + }; + break; + case /* avalanche.operator.NodeStatusChanged node_status_changed */ 4: + message.change = { + oneofKind: "nodeStatusChanged", + nodeStatusChanged: NodeStatusChanged.internalBinaryRead(reader, reader.uint32(), options, (message.change as any).nodeStatusChanged) + }; + break; + case /* avalanche.operator.LogAppended log_appended */ 5: + message.change = { + oneofKind: "logAppended", + logAppended: LogAppended.internalBinaryRead(reader, reader.uint32(), options, (message.change as any).logAppended) + }; + break; + case /* avalanche.operator.AgentEventAppended agent_event_appended */ 6: + message.change = { + oneofKind: "agentEventAppended", + agentEventAppended: AgentEventAppended.internalBinaryRead(reader, reader.uint32(), options, (message.change as any).agentEventAppended) + }; + break; + case /* avalanche.operator.TraceFinalized trace_finalized */ 7: + message.change = { + oneofKind: "traceFinalized", + traceFinalized: TraceFinalized.internalBinaryRead(reader, reader.uint32(), options, (message.change as any).traceFinalized) + }; + break; + case /* avalanche.operator.CatalogReplaced catalog_replaced */ 8: + message.change = { + oneofKind: "catalogReplaced", + catalogReplaced: CatalogReplaced.internalBinaryRead(reader, reader.uint32(), options, (message.change as any).catalogReplaced) + }; + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: OperatorUpdate, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint64 sequence = 1; */ + if (message.sequence !== "0") + writer.tag(1, WireType.Varint).uint64(message.sequence); + /* avalanche.operator.RunCreated run_created = 2; */ + if (message.change.oneofKind === "runCreated") + RunCreated.internalBinaryWrite(message.change.runCreated, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + /* avalanche.operator.RunStatusChanged run_status_changed = 3; */ + if (message.change.oneofKind === "runStatusChanged") + RunStatusChanged.internalBinaryWrite(message.change.runStatusChanged, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + /* avalanche.operator.NodeStatusChanged node_status_changed = 4; */ + if (message.change.oneofKind === "nodeStatusChanged") + NodeStatusChanged.internalBinaryWrite(message.change.nodeStatusChanged, writer.tag(4, WireType.LengthDelimited).fork(), options).join(); + /* avalanche.operator.LogAppended log_appended = 5; */ + if (message.change.oneofKind === "logAppended") + LogAppended.internalBinaryWrite(message.change.logAppended, writer.tag(5, WireType.LengthDelimited).fork(), options).join(); + /* avalanche.operator.AgentEventAppended agent_event_appended = 6; */ + if (message.change.oneofKind === "agentEventAppended") + AgentEventAppended.internalBinaryWrite(message.change.agentEventAppended, writer.tag(6, WireType.LengthDelimited).fork(), options).join(); + /* avalanche.operator.TraceFinalized trace_finalized = 7; */ + if (message.change.oneofKind === "traceFinalized") + TraceFinalized.internalBinaryWrite(message.change.traceFinalized, writer.tag(7, WireType.LengthDelimited).fork(), options).join(); + /* avalanche.operator.CatalogReplaced catalog_replaced = 8; */ + if (message.change.oneofKind === "catalogReplaced") + CatalogReplaced.internalBinaryWrite(message.change.catalogReplaced, writer.tag(8, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.OperatorUpdate + */ +export const OperatorUpdate = new OperatorUpdate$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class ResetRequired$Type extends MessageType { + constructor() { + super("avalanche.operator.ResetRequired", [ + { no: 1, name: "history_floor", kind: "scalar", T: 4 /*ScalarType.UINT64*/ }, + { no: 2, name: "latest_sequence", kind: "scalar", T: 4 /*ScalarType.UINT64*/ } + ]); + } + create(value?: PartialMessage): ResetRequired { + const message = globalThis.Object.create((this.messagePrototype!)); + message.historyFloor = "0"; + message.latestSequence = "0"; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: ResetRequired): ResetRequired { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* uint64 history_floor */ 1: + message.historyFloor = reader.uint64().toString(); + break; + case /* uint64 latest_sequence */ 2: + message.latestSequence = reader.uint64().toString(); + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: ResetRequired, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* uint64 history_floor = 1; */ + if (message.historyFloor !== "0") + writer.tag(1, WireType.Varint).uint64(message.historyFloor); + /* uint64 latest_sequence = 2; */ + if (message.latestSequence !== "0") + writer.tag(2, WireType.Varint).uint64(message.latestSequence); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.ResetRequired + */ +export const ResetRequired = new ResetRequired$Type(); +// @generated message type with reflection information, may provide speed optimized methods +class OperatorUpdateEnvelope$Type extends MessageType { + constructor() { + super("avalanche.operator.OperatorUpdateEnvelope", [ + { no: 1, name: "operator_instance_id", kind: "scalar", T: 9 /*ScalarType.STRING*/ }, + { no: 2, name: "update", kind: "message", oneof: "payload", T: () => OperatorUpdate }, + { no: 3, name: "reset_required", kind: "message", oneof: "payload", T: () => ResetRequired } + ]); + } + create(value?: PartialMessage): OperatorUpdateEnvelope { + const message = globalThis.Object.create((this.messagePrototype!)); + message.operatorInstanceId = ""; + message.payload = { oneofKind: undefined }; + if (value !== undefined) + reflectionMergePartial(this, message, value); + return message; + } + internalBinaryRead(reader: IBinaryReader, length: number, options: BinaryReadOptions, target?: OperatorUpdateEnvelope): OperatorUpdateEnvelope { + let message = target ?? this.create(), end = reader.pos + length; + while (reader.pos < end) { + let [fieldNo, wireType] = reader.tag(); + switch (fieldNo) { + case /* string operator_instance_id */ 1: + message.operatorInstanceId = reader.string(); + break; + case /* avalanche.operator.OperatorUpdate update */ 2: + message.payload = { + oneofKind: "update", + update: OperatorUpdate.internalBinaryRead(reader, reader.uint32(), options, (message.payload as any).update) + }; + break; + case /* avalanche.operator.ResetRequired reset_required */ 3: + message.payload = { + oneofKind: "resetRequired", + resetRequired: ResetRequired.internalBinaryRead(reader, reader.uint32(), options, (message.payload as any).resetRequired) + }; + break; + default: + let u = options.readUnknownField; + if (u === "throw") + throw new globalThis.Error(`Unknown field ${fieldNo} (wire type ${wireType}) for ${this.typeName}`); + let d = reader.skip(wireType); + if (u !== false) + (u === true ? UnknownFieldHandler.onRead : u)(this.typeName, message, fieldNo, wireType, d); + } + } + return message; + } + internalBinaryWrite(message: OperatorUpdateEnvelope, writer: IBinaryWriter, options: BinaryWriteOptions): IBinaryWriter { + /* string operator_instance_id = 1; */ + if (message.operatorInstanceId !== "") + writer.tag(1, WireType.LengthDelimited).string(message.operatorInstanceId); + /* avalanche.operator.OperatorUpdate update = 2; */ + if (message.payload.oneofKind === "update") + OperatorUpdate.internalBinaryWrite(message.payload.update, writer.tag(2, WireType.LengthDelimited).fork(), options).join(); + /* avalanche.operator.ResetRequired reset_required = 3; */ + if (message.payload.oneofKind === "resetRequired") + ResetRequired.internalBinaryWrite(message.payload.resetRequired, writer.tag(3, WireType.LengthDelimited).fork(), options).join(); + let u = options.writeUnknownFields; + if (u !== false) + (u == true ? UnknownFieldHandler.onWrite : u)(this.typeName, message, writer); + return writer; + } +} +/** + * @generated MessageType for protobuf message avalanche.operator.OperatorUpdateEnvelope + */ +export const OperatorUpdateEnvelope = new OperatorUpdateEnvelope$Type(); +/** + * @generated ServiceType for protobuf service avalanche.operator.OperatorService + */ +export const OperatorService = new ServiceType("avalanche.operator.OperatorService", [ + { name: "GetCatalog", options: {}, I: Empty, O: CatalogSnapshotMsg }, + { name: "StartRun", options: {}, I: StartRunRequest, O: StartRunResponse }, + { name: "CancelRun", options: {}, I: CancelRunRequest, O: Empty }, + { name: "GetRunResult", options: {}, I: GetRunRequest, O: RunResultMsg }, + { name: "ListRunSummaries", options: {}, I: ListRunSummariesRequest, O: RunSummaryPage }, + { name: "GetRunSnapshot", options: {}, I: GetRunSnapshotRequest, O: RunSnapshotMsg }, + { name: "GetLatestRunSnapshot", options: {}, I: GetLatestRunSnapshotRequest, O: RunSnapshotMsg }, + { name: "ListLogs", options: {}, I: ListLogsRequest, O: LogPage }, + { name: "ListAgentEvents", options: {}, I: ListAgentEventsRequest, O: AgentEventPage }, + { name: "ReadTrace", serverStreaming: true, options: {}, I: ReadTraceRequest, O: TraceChunk }, + { name: "ReadDetail", serverStreaming: true, options: {}, I: ReadDetailRequest, O: DetailChunk }, + { name: "StreamOperatorUpdates", serverStreaming: true, options: {}, I: StreamOperatorUpdatesRequest, O: OperatorUpdateEnvelope } +]); diff --git a/web/operator/src/guards.ts b/web/operator/src/guards.ts new file mode 100644 index 0000000..3b1609e --- /dev/null +++ b/web/operator/src/guards.ts @@ -0,0 +1,3 @@ +export function isUnknownRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} diff --git a/web/operator/src/main.tsx b/web/operator/src/main.tsx new file mode 100644 index 0000000..1ce58f6 --- /dev/null +++ b/web/operator/src/main.tsx @@ -0,0 +1,16 @@ +import "@xyflow/react/dist/style.css"; +import { StrictMode } from "react"; +import { createRoot } from "react-dom/client"; + +import { GrpcWebOperatorApi } from "./api"; +import { App } from "./App"; +import "./style.css"; + +const root = document.getElementById("root"); +if (!root) throw new Error("Operator UI root element is missing"); + +createRoot(root).render( + + + , +); diff --git a/web/operator/src/operator.large-run.benchmark.test.tsx b/web/operator/src/operator.large-run.benchmark.test.tsx new file mode 100644 index 0000000..c563f4f --- /dev/null +++ b/web/operator/src/operator.large-run.benchmark.test.tsx @@ -0,0 +1,626 @@ + +import { Profiler, useEffect } from "react"; +import { act, fireEvent, render, screen, waitFor, within } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +// The production virtualizer is exercised by benchmark:browser. This unit volume +// gate isolates projection, paging, cache, and mounted-row bounds from jsdom layout. +vi.mock("@tanstack/react-virtual", () => ({ + useVirtualizer: ({ count }: { count: number }) => ({ + getTotalSize: () => count * 32, + getVirtualItems: () => + Array.from({ length: Math.min(count, 120) }, (_, index) => ({ + index, + size: 32, + start: index * 32, + })), + scrollToIndex: () => undefined, + }), +})); + + +import type { OperatorApi, StructuralBaseline } from "./api"; +import { RunListPanel } from "./RunListPanel"; +import { + AgentEventDescriptorMsg, + CatalogSnapshotMsg, + DescriptorPageOrder, + LogRecordDescriptorMsg, + OperatorUpdateEnvelope, + RunSnapshotMsg, + RunSummaryMsg, + WorkflowTopologyMsg, +} from "./generated/operator"; +import { Inspector } from "./Inspector"; +import { RunLogPane } from "./RunLogPane"; +import { useOperatorProjection } from "./state"; + +const OPERATOR_ID = "benchmark-operator"; +const WORKFLOW_ID = "benchmark.py::large_run"; +const RUN_ID = "run-09999"; +const SELECTED_NODE = "node-042"; +const RUN_SUMMARY_COUNT = 10_000; +const NODE_COUNT = 100; +const LOGS_PER_NODE = 500; +const LOG_DESCRIPTOR_COUNT = NODE_COUNT * LOGS_PER_NODE; +const AGENT_EVENT_COUNT = 20_000; +const ENVELOPE_COUNT = 1_000; +const PAGE_SIZE = 100; +const DOM_ROW_LIMIT = 120; +const LARGE_DETAIL_BYTES = 2 * 1024 * 1024; +const UNIT_RENDER_BUDGET_MS = 10_000; + +function summary(index: number) { + return RunSummaryMsg.create({ + runId: `run-${index.toString().padStart(5, "0")}`, + workflowId: WORKFLOW_ID, + workflowDisplayName: "Benchmark flow", + status: index % 7 === 0 ? "failed" : "success", + startedAt: index + 1, + endedAt: index + 2, + createdSequence: String(index + 1), + revision: String(index + 1), + }); +} + +const runSummaries = Array.from({ length: RUN_SUMMARY_COUNT }, (_, index) => summary(index)); +const catalog = CatalogSnapshotMsg.create({ + operatorInstanceId: OPERATOR_ID, + asOfSequence: "0", + revision: "1", + scanTargets: [ + { alias: "bench", targetPath: "/controlled/bench", kind: "directory" }, + ], + workflows: [ + { + workflowId: WORKFLOW_ID, + displayName: "Benchmark flow", + rootAlias: "bench", + relativeFile: "benchmark.py", + builderSymbol: "large_run", + nodeIds: Array.from({ length: NODE_COUNT }, (_, index) => + `node-${index.toString().padStart(3, "0")}`, + ), + graph: {}, + nodeTypes: {}, + displayNames: {}, + agentNodeIds: [SELECTED_NODE], + agentMetadataJson: {}, + }, + ], +}); +const baseline: StructuralBaseline = { catalog, asOfSequence: "0", runs: runSummaries }; + +const topology = WorkflowTopologyMsg.create({ + nodeIds: catalog.workflows[0].nodeIds, + graph: Object.fromEntries(catalog.workflows[0].nodeIds.map((nodeId) => [nodeId, { children: [] }])), + nodeTypes: Object.fromEntries(catalog.workflows[0].nodeIds.map((nodeId) => [nodeId, "task"])), + displayNames: Object.fromEntries( + catalog.workflows[0].nodeIds.map((nodeId) => [nodeId, `Benchmark ${nodeId}`]), + ), +}); +const selectedRun = RunSnapshotMsg.create({ + operatorInstanceId: OPERATOR_ID, + asOfSequence: "0", + summary: runSummaries.at(-1), + topology, + nodes: catalog.workflows[0].nodeIds.map((nodeId) => ({ + nodeId, + name: nodeId, + nodeType: "task", + status: "success", + startedAt: 1, + endedAt: 2, + revision: "1", + eventPageToken: nodeId === SELECTED_NODE ? "events:0" : "", + })), + latestLogSequence: String(LOG_DESCRIPTOR_COUNT), + logPageToken: "logs:0", +}); + +const logDescriptors = Array.from({ length: LOG_DESCRIPTOR_COUNT }, (_, index) => { + const nodeIndex = Math.floor(index / LOGS_PER_NODE); + const nodeId = `node-${nodeIndex.toString().padStart(3, "0")}`; + return LogRecordDescriptorMsg.create({ + sequence: String(index + 1), + nodeId, + timestamp: index + 1, + level: index % 11 === 0 ? "warning" : "info", + sizeBytes: "64", + bodyToken: `log:${nodeId}:${index + 1}`, + }); +}); +const agentEvents = Array.from({ length: AGENT_EVENT_COUNT }, (_, index) => + AgentEventDescriptorMsg.create({ + eventSequence: String(index + 1), + sizeBytes: String(LARGE_DETAIL_BYTES), + bodyToken: + index === 0 + ? "detail:input" + : index === AGENT_EVENT_COUNT - 1 + ? "detail:output" + : `event:${index + 1}`, + invocationId: `invocation-${Math.floor(index / 10)}`, + eventKind: + index === 0 + ? "run.started" + : index === AGENT_EVENT_COUNT - 1 + ? "run.succeeded" + : "iteration.recorded", + iteration: index > 0 && index < AGENT_EVENT_COUNT - 1 ? index : 0, + durationMs: "1", + toolCount: index % 3, + predictCount: index % 2, + }), +); + +function deferred() { + return Promise.withResolvers(); +} + + +function untilAborted(signal?: AbortSignal) { + const { promise, resolve } = Promise.withResolvers(); + if (!signal || signal.aborted) { + resolve(); + } else { + signal.addEventListener("abort", () => resolve(), { once: true }); + } + return promise; +} + +class ManualFrameScheduler { + private nextId = 1; + readonly callbacks = new Map(); + + install() { + vi.stubGlobal("requestAnimationFrame", (callback: FrameRequestCallback) => { + const id = this.nextId; + this.nextId += 1; + this.callbacks.set(id, callback); + return id; + }); + vi.stubGlobal("cancelAnimationFrame", (id: number) => { + this.callbacks.delete(id); + }); + } + + async flushOne() { + const entry = this.callbacks.entries().next().value as + | [number, FrameRequestCallback] + | undefined; + if (!entry) throw new Error("No scheduled animation frame"); + this.callbacks.delete(entry[0]); + await act(async () => { + entry[1](this.nextId * 16); + await Promise.resolve(); + }); + } +} + +function liveEnvelope(sequence: number) { + const descriptorSequence = String(Math.floor((sequence + 1) / 2)); + const change = + sequence % 2 === 1 + ? { + oneofKind: "logAppended" as const, + logAppended: { + runId: RUN_ID, + log: LogRecordDescriptorMsg.create({ + sequence: descriptorSequence, + nodeId: SELECTED_NODE, + timestamp: sequence, + level: "info", + sizeBytes: "32", + bodyToken: `live-log:${descriptorSequence}`, + }), + }, + } + : { + oneofKind: "agentEventAppended" as const, + agentEventAppended: { + runId: RUN_ID, + nodeId: SELECTED_NODE, + event: AgentEventDescriptorMsg.create({ + eventSequence: descriptorSequence, + sizeBytes: "32", + bodyToken: `live-event:${descriptorSequence}`, + eventKind: "iteration.recorded", + invocationId: "live", + }), + }, + }; + return OperatorUpdateEnvelope.create({ + operatorInstanceId: OPERATOR_ID, + payload: { + oneofKind: "update", + update: { sequence: String(sequence), change }, + }, + }); +} + +function ProjectionProbe({ + api, + observedSequences, +}: { + api: OperatorApi; + observedSequences: string[]; +}) { + const projection = useOperatorProjection(api); + const { state } = projection; + useEffect(() => { + observedSequences.push(state.sequence); + }, [observedSequences, state.sequence]); + return ( +
+ + {Object.keys(state.runs).length} + {state.sequence} + + {state.liveLogs[RUN_ID]?.length ?? 0} + + + {state.liveEvents[`${RUN_ID}:${SELECTED_NODE}`]?.length ?? 0} + +
+ ); +} + +function decodedSplitText() { + const expected = "plain text A😀B: not JSON }"; + const encoded = new TextEncoder().encode(expected); + const splitAt = encoded.indexOf(0xf0) + 2; + const decoder = new TextDecoder(); + return decoder.decode(encoded.slice(0, splitAt), { stream: true }) + decoder.decode(encoded.slice(splitAt)); +} + + +afterEach(() => { + vi.unstubAllGlobals(); +}); + +describe("large retained-run browser benchmark", () => { + it( + "bounds summary DOM and frame-batches 1,000 ordered live envelopes", + async () => { + expect(runSummaries).toHaveLength(RUN_SUMMARY_COUNT); + const scheduler = new ManualFrameScheduler(); + scheduler.install(); + const startUpdates = deferred(); + let yieldedUpdates = 0; + const getLatestRunSnapshot = vi.fn(async () => + RunSnapshotMsg.create({ + ...selectedRun, + asOfSequence: String(yieldedUpdates), + }), + ); + const api: OperatorApi = { + getCatalog: async () => catalog, + loadBaseline: vi.fn(async () => baseline), + getLatestRunSnapshot, + streamUpdates: async function* (_operatorInstanceId, _afterSequence, signal) { + await startUpdates.promise; + for (let sequence = 1; sequence <= ENVELOPE_COUNT; sequence += 1) { + yieldedUpdates += 1; + yield liveEnvelope(sequence); + } + await untilAborted(signal); + }, + listLogPage: async () => { + throw new Error("unused"); + }, + listAgentEventPage: async () => { + throw new Error("unused"); + }, + readJsonDetail: async () => { + throw new Error("unused"); + }, + readTextDetail: async () => { + throw new Error("unused"); + }, + startRun: async () => RUN_ID, + cancelRun: async () => undefined, + }; + const observedSequences: string[] = []; + const projectionView = render( + , + ); + + await waitFor(() => + expect(screen.getByTestId("run-count")).toHaveTextContent(String(RUN_SUMMARY_COUNT)), + ); + expect(getLatestRunSnapshot).not.toHaveBeenCalled(); + + fireEvent.click(screen.getByRole("button", { name: "Select benchmark run" })); + await waitFor(() => expect(getLatestRunSnapshot).toHaveBeenCalledTimes(1)); + startUpdates.resolve(); + await waitFor(() => expect(yieldedUpdates).toBe(ENVELOPE_COUNT)); + await waitFor(() => expect(scheduler.callbacks.size).toBe(1)); + + expect(screen.getByTestId("projection-sequence")).toHaveTextContent("0"); + while (scheduler.callbacks.size > 0) await scheduler.flushOne(); + + await waitFor(() => + expect(screen.getByTestId("projection-sequence")).toHaveTextContent( + String(ENVELOPE_COUNT), + ), + ); + expect(Number(screen.getByTestId("live-log-count").textContent)).toBeLessThanOrEqual(256); + expect(Number(screen.getByTestId("live-event-count").textContent)).toBeLessThanOrEqual(256); + const committedSequences = observedSequences + .map(Number) + .filter((value, index, values) => index === 0 || value !== values[index - 1]); + const frameDeltas = committedSequences + .slice(1) + .map((value, index) => value - committedSequences[index]) + .filter((delta) => delta > 0); + expect(frameDeltas.length).toBeGreaterThan(1); + expect(Math.max(...frameDeltas)).toBeLessThanOrEqual(256); + projectionView.unmount(); + + const onSelectRun = vi.fn(); + const runListRenderStart = performance.now(); + const runListView = render( + [item.runId, item]))} + onSelectRun={onSelectRun} + />, + ); + const virtualRunList = await within(runListView.container).findByRole("region", { + name: "Workflow runs", + }); + const newestRun = await within(virtualRunList).findByRole("button", { + name: /run-09999/, + }); + expect(virtualRunList.querySelectorAll(".run-list-row").length).toBeLessThanOrEqual( + DOM_ROW_LIMIT, + ); + expect(performance.now() - runListRenderStart).toBeLessThan(UNIT_RENDER_BUDGET_MS); + fireEvent.click(newestRun); + expect(onSelectRun).toHaveBeenLastCalledWith(RUN_ID); + + }, + 30_000, + ); + + it( + "pages controlled descriptor volumes and suppresses stale large details", + async () => { + expect(logDescriptors).toHaveLength(LOG_DESCRIPTOR_COUNT); + expect(new Set(logDescriptors.map((entry) => entry.nodeId)).size).toBe(NODE_COUNT); + expect(agentEvents).toHaveLength(AGENT_EVENT_COUNT); + const staleInput = deferred(); + const freshOutput = deferred(); + const largePayload = "x".repeat(LARGE_DETAIL_BYTES); + const selectedLogs = logDescriptors.filter((entry) => entry.nodeId === SELECTED_NODE); + const listAgentEventPage = vi.fn(async (request) => { + if (request.order === DescriptorPageOrder.NEWEST_FIRST) { + const upper = + request.beforeEventSequence === "0" + ? agentEvents.length + : Number(request.beforeEventSequence) - 1; + const lower = Math.max(1, upper - request.pageSize + 1); + return { + operatorInstanceId: OPERATOR_ID, + asOfSequence: selectedRun.asOfSequence, + runId: RUN_ID, + nodeId: SELECTED_NODE, + records: agentEvents.slice(lower - 1, upper).reverse(), + nextPageToken: lower === 1 ? "" : "events:older", + nextCursor: String(lower), + }; + } + const start = Number(request.afterEventSequence); + const records = agentEvents.slice(start, start + request.pageSize); + return { + operatorInstanceId: OPERATOR_ID, + asOfSequence: selectedRun.asOfSequence, + runId: RUN_ID, + nodeId: SELECTED_NODE, + records, + nextPageToken: start + records.length >= agentEvents.length ? "" : "events:next", + nextCursor: records.at(-1)?.eventSequence ?? request.afterEventSequence, + }; + }); + const listLogPage = vi.fn(async (request) => { + const end = + request.beforeSequence === "0" + ? selectedLogs.length + : selectedLogs.findIndex((entry) => entry.sequence === request.beforeSequence); + const records = selectedLogs + .slice(Math.max(0, end - request.pageSize), end) + .reverse(); + return { + operatorInstanceId: OPERATOR_ID, + asOfSequence: selectedRun.asOfSequence, + records, + nextPageToken: end === selectedLogs.length ? "logs:next" : "logs:next-2", + nextCursor: records.at(-1)?.sequence ?? request.beforeSequence, + }; + }); + const readJsonDetail = vi.fn((bodyToken) => { + if (bodyToken === "detail:input") return staleInput.promise; + if (bodyToken === "detail:output") return freshOutput.promise; + return Promise.resolve({ event: bodyToken, payload: largePayload }); + }); + const readTextDetail = vi.fn(async () => decodedSplitText()); + const api: OperatorApi = { + getCatalog: async () => catalog, + loadBaseline: async () => baseline, + getLatestRunSnapshot: async () => selectedRun, + streamUpdates: async function* () { + return; + }, + listAgentEventPage, + listLogPage, + readJsonDetail, + readTextDetail, + startRun: async () => RUN_ID, + cancelRun: async () => undefined, + }; + let inspectorCommits = 0; + const benchmarkStart = performance.now(); + render( + { inspectorCommits += 1; }}> + undefined} + /> + , + ); + + expect(listAgentEventPage).not.toHaveBeenCalled(); + expect(listLogPage).not.toHaveBeenCalled(); + expect(readJsonDetail).not.toHaveBeenCalled(); + expect(readTextDetail).not.toHaveBeenCalled(); + + fireEvent.click(screen.getByRole("button", { name: "inputs" })); + await waitFor(() => + expect(readJsonDetail.mock.calls.some(([token]) => token === "detail:input")).toBe(true), + ); + expect(listAgentEventPage).toHaveBeenCalledTimes(1); + expect(listAgentEventPage.mock.calls[0][0]).toMatchObject({ + pageToken: "events:0", + afterEventSequence: "0", + pageSize: PAGE_SIZE, + order: DescriptorPageOrder.FORWARD, + expectedNodeId: SELECTED_NODE, + }); + + fireEvent.click(screen.getByRole("button", { name: "output" })); + await waitFor(() => + expect(readJsonDetail.mock.calls.some(([token]) => token === "detail:output")).toBe(true), + ); + expect(listAgentEventPage).toHaveBeenCalledTimes(2); + expect(listAgentEventPage.mock.calls[1][0]).toMatchObject({ + beforeEventSequence: "0", + order: DescriptorPageOrder.NEWEST_FIRST, + expectedNodeId: SELECTED_NODE, + }); + const outputDetail = { + data: { outputs: { freshMarker: "fresh-detail", payload: largePayload } }, + }; + expect(JSON.stringify(outputDetail).length).toBeGreaterThanOrEqual(LARGE_DETAIL_BYTES); + await act(async () => { + freshOutput.resolve(outputDetail); + await Promise.resolve(); + }); + const outputTree = await screen.findByRole("tree", { name: "JSON value" }); + expect(within(outputTree).getByText("fresh-detail")).toBeInTheDocument(); + expect(within(outputTree).getByText("freshMarker")).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Object/ })).not.toBeInTheDocument(); + + const commitsBeforeStaleCompletion = inspectorCommits; + await act(async () => { + staleInput.resolve({ data: { inputs: { staleMarker: "stale-detail" } } }); + await Promise.resolve(); + }); + expect(inspectorCommits).toBe(commitsBeforeStaleCompletion); + expect(screen.queryByText("stale-detail")).not.toBeInTheDocument(); + expect(screen.getByText("fresh-detail")).toBeInTheDocument(); + + fireEvent.click(screen.getByRole("button", { name: "inputs" })); + const inputTree = await screen.findByRole("tree", { name: "JSON value" }); + expect(listAgentEventPage).toHaveBeenCalledTimes(3); + expect(within(inputTree).getByText("stale-detail")).toBeInTheDocument(); + expect(screen.queryByRole("button", { name: /Object/ })).not.toBeInTheDocument(); + + fireEvent.click(screen.getByRole("button", { name: "Load more events" })); + await waitFor(() => { + expect(listAgentEventPage).toHaveBeenCalledTimes(4); + expect(screen.getByRole("button", { name: "Load more events" })).not.toBeDisabled(); + }); + expect(listAgentEventPage).toHaveBeenCalledTimes(4); + expect(listAgentEventPage.mock.calls[3][0]).toMatchObject({ + pageToken: "events:next", + afterEventSequence: String(PAGE_SIZE), + pageSize: PAGE_SIZE, + order: DescriptorPageOrder.FORWARD, + expectedNodeId: SELECTED_NODE, + }); + + fireEvent.click(screen.getByRole("button", { name: "trace" })); + expect(await screen.findByText("99 retained turns")).toBeInTheDocument(); + expect(listAgentEventPage).toHaveBeenCalledTimes(5); + expect(listAgentEventPage.mock.calls[4][0]).toMatchObject({ + pageToken: "events:0", + afterEventSequence: "0", + pageSize: PAGE_SIZE, + order: DescriptorPageOrder.FORWARD, + expectedNodeId: SELECTED_NODE, + }); + fireEvent.click(screen.getByRole("button", { name: "Expand turns" })); + await waitFor(() => expect(listAgentEventPage).toHaveBeenCalledTimes(6)); + expect(listAgentEventPage.mock.calls[5][0]).toMatchObject({ + pageToken: "events:next", + afterEventSequence: String(PAGE_SIZE), + pageSize: PAGE_SIZE, + order: DescriptorPageOrder.FORWARD, + expectedNodeId: SELECTED_NODE, + }); + fireEvent.click(screen.getByRole("button", { name: "Following live" })); + for (let turn = 0; turn < 5; turn += 1) { + const token = `event:${turn + 2}`; + fireEvent.click(await screen.findByRole("button", { name: `Expand ${turn}` })); + await waitFor(() => + expect(readJsonDetail.mock.calls.filter(([called]) => called === token)).toHaveLength(1), + ); + expect(await screen.findByText(token)).toBeInTheDocument(); + } + fireEvent.click(screen.getByRole("button", { name: "Collapse 0" })); + fireEvent.click(screen.getByRole("button", { name: "Expand 0" })); + await waitFor(() => + expect(readJsonDetail.mock.calls.filter(([token]) => token === "event:2")).toHaveLength(2), + ); + + const logPaneView = render( + undefined} + />, + ); + const logPane = await within(logPaneView.container).findByRole("region", { + name: "Run logs", + }); + await waitFor(() => expect(listLogPage).toHaveBeenCalledTimes(1)); + expect(listLogPage.mock.calls[0][0]).toMatchObject({ + pageSize: PAGE_SIZE, + nodeId: SELECTED_NODE, + order: DescriptorPageOrder.NEWEST_FIRST, + }); + await waitFor(() => expect(readTextDetail).toHaveBeenCalledTimes(PAGE_SIZE)); + const initialLogRows = logPane.querySelectorAll(".run-log-row"); + expect(initialLogRows).toHaveLength(PAGE_SIZE); + expect( + Array.from(initialLogRows).every( + (row) => row.querySelector("pre")?.textContent === decodedSplitText(), + ), + ).toBe(true); + expect(document.querySelector(".inspector-log-stream")).not.toBeInTheDocument(); + + fireEvent.click(within(logPane).getByRole("button", { name: "Load older logs" })); + await waitFor(() => expect(listLogPage).toHaveBeenCalledTimes(2)); + expect(listLogPage.mock.calls[1][0]).toMatchObject({ + pageToken: "logs:next", + beforeSequence: selectedLogs.at(-PAGE_SIZE)?.sequence, + pageSize: PAGE_SIZE, + nodeId: SELECTED_NODE, + order: DescriptorPageOrder.NEWEST_FIRST, + }); + await waitFor(() => expect(readTextDetail).toHaveBeenCalledTimes(PAGE_SIZE * 2)); + expect(logPane.querySelectorAll(".run-log-row").length).toBeLessThanOrEqual(DOM_ROW_LIMIT); + expect(listLogPage).toHaveBeenCalledTimes(2); + expect(performance.now() - benchmarkStart).toBeLessThan(30_000); + }, + 30_000, + ); + +}); diff --git a/web/operator/src/state.test.ts b/web/operator/src/state.test.ts new file mode 100644 index 0000000..56f0091 --- /dev/null +++ b/web/operator/src/state.test.ts @@ -0,0 +1,944 @@ +import { act, renderHook, waitFor } from "@testing-library/react"; +import { afterEach, describe, expect, it, vi } from "vitest"; + +import type { OperatorApi, StructuralBaseline } from "./api"; +import { + AgentEventDescriptorMsg, + CatalogSnapshotMsg, + FlowInfoMsg, + LogRecordDescriptorMsg, + NodeSnapshotMsg, + type OperatorUpdate, + OperatorUpdateEnvelope, + RunSnapshotMsg, + RunSummaryMsg, + TraceDescriptorMsg, + WorkflowTopologyMsg, +} from "./generated/operator"; +import { emptyProjection, projectionReducer, useOperatorProjection } from "./state"; + +const workflow = FlowInfoMsg.create({ + name: "orders", + displayName: "Orders", + workflowId: "flows.py::orders", + rootAlias: "examples", + relativeFile: "flows.py", + nodeIds: ["fetch"], + graph: { fetch: { children: [] } }, + nodeTypes: { fetch: "step" }, + displayNames: { fetch: "Fetch" }, +}); +const summary = RunSummaryMsg.create({ + runId: "run-1", + flowName: "orders", + workflowId: workflow.workflowId, + workflowDisplayName: workflow.displayName, + status: "running", + createdSequence: "1", + revision: "1", +}); +const secondSummary = RunSummaryMsg.create({ + ...summary, + runId: "run-2", + createdSequence: "2", +}); +const node = NodeSnapshotMsg.create({ + nodeId: "fetch", + name: "Fetch", + nodeType: "step", + status: "running", + revision: "1", +}); +const topology = WorkflowTopologyMsg.create({ + nodeIds: ["fetch"], + graph: { fetch: { children: [] } }, + nodeTypes: { fetch: "step" }, + displayNames: { fetch: "Fetch" }, +}); +const baseline: StructuralBaseline = { + catalog: CatalogSnapshotMsg.create({ + operatorInstanceId: "operator-1", + asOfSequence: "1", + revision: "1", + workflows: [workflow], + }), + asOfSequence: "1", + runs: [summary], +}; + +function snapshotFor(run: RunSummaryMsg): RunSnapshotMsg { + return RunSnapshotMsg.create({ + operatorInstanceId: "operator-1", + asOfSequence: "1", + summary: run, + nodes: [node], + topology, + }); +} + +function envelope( + sequence: string, + change: OperatorUpdate["change"] = { oneofKind: undefined }, + operatorInstanceId = "operator-1", +): OperatorUpdateEnvelope { + return OperatorUpdateEnvelope.create({ + operatorInstanceId, + payload: { oneofKind: "update", update: { sequence, change } }, + }); +} + +function selectedState(run = summary) { + const state = projectionReducer(emptyProjection, { + type: "baseline", + baseline: { ...baseline, runs: [summary, secondSummary] }, + }); + const loading = projectionReducer(state, { + type: "selectionLoading", + runId: run.runId, + }); + return projectionReducer(loading, { + type: "selectionReady", + runId: run.runId, + snapshot: snapshotFor(run), + }); +} + +async function* idleUpdates(signal?: AbortSignal): AsyncIterable { + await new Promise((resolve) => { + if (signal?.aborted) { + resolve(); + return; + } + signal?.addEventListener("abort", () => resolve(), { once: true }); + }); +} + +type ProjectionApi = Pick< + OperatorApi, + "loadBaseline" | "getLatestRunSnapshot" | "streamUpdates" | "startRun" | "cancelRun" +>; + +function createApi(overrides: Partial = {}): OperatorApi { + const defaults: ProjectionApi = { + loadBaseline: async () => baseline, + getLatestRunSnapshot: async (runId) => + snapshotFor(runId === secondSummary.runId ? secondSummary : summary), + streamUpdates: (_operatorInstanceId, _afterSequence, signal) => idleUpdates(signal), + startRun: async () => "run-3", + cancelRun: async () => undefined, + }; + return { ...defaults, ...overrides } as OperatorApi; +} + +function deferred() { + let resolve!: (value: T) => void; + const promise = new Promise((done) => { + resolve = done; + }); + return { promise, resolve }; +} + +afterEach(() => { + vi.restoreAllMocks(); +}); + +describe("projectionReducer", () => { + it("installs summary-only baselines and clears selected ephemeral state", () => { + const previous = { + ...selectedState(), + liveLogs: { "run-1": [LogRecordDescriptorMsg.create({ sequence: "1" })] }, + liveEvents: { + "run-1:fetch": [AgentEventDescriptorMsg.create({ eventSequence: "1" })], + }, + liveLogRepairWatermarks: { "run-1": "1" }, + liveEventRepairWatermarks: { "run-1:fetch": "1" }, + }; + + const state = projectionReducer(previous, { type: "baseline", baseline }); + + expect(state.runs).toEqual({ "run-1": summary }); + expect(state.runs[summary.runId]).not.toHaveProperty("nodes"); + expect(state.selectedRun).toBeUndefined(); + expect(state.selectedRunStatus).toBe("idle"); + expect(state.liveLogs).toEqual({}); + expect(state.liveEvents).toEqual({}); + expect(state.liveLogRepairWatermarks).toEqual({}); + expect(state.liveEventRepairWatermarks).toEqual({}); + }); + + it("applies status to the summary and selected snapshot and detail only to the selection", () => { + let state = selectedState(); + state = projectionReducer(state, { + type: "envelopes", + envelopes: [ + envelope("2", { + oneofKind: "runStatusChanged", + runStatusChanged: { + runId: summary.runId, + status: "failed", + startedAt: 10, + endedAt: 12, + revision: "2", + }, + }), + envelope("3", { + oneofKind: "nodeStatusChanged", + nodeStatusChanged: { + runId: summary.runId, + nodeId: "fetch", + status: "failed", + startedAt: 10, + endedAt: 12, + revision: "2", + error: "source unavailable", + }, + }), + envelope("4", { + oneofKind: "traceFinalized", + traceFinalized: { + runId: summary.runId, + nodeId: "fetch", + trace: TraceDescriptorMsg.create({ status: "failed", revision: "2" }), + }, + }), + ], + }); + + expect(state.runs[summary.runId]).toMatchObject({ status: "failed", revision: "2" }); + expect(state.selectedRun?.summary).toMatchObject({ status: "failed", revision: "2" }); + expect(state.selectedRun?.nodes[0]).toMatchObject({ + status: "failed", + error: "source unavailable", + trace: { status: "failed" }, + }); + }); + + it("ignores node, trace, log, and event detail for an unselected run", () => { + const original = selectedState(); + const state = projectionReducer(original, { + type: "envelopes", + envelopes: [ + envelope("2", { + oneofKind: "nodeStatusChanged", + nodeStatusChanged: { + runId: secondSummary.runId, + nodeId: "fetch", + status: "failed", + revision: "2", + startedAt: 1, + endedAt: 2, + }, + }), + envelope("3", { + oneofKind: "traceFinalized", + traceFinalized: { + runId: secondSummary.runId, + nodeId: "fetch", + trace: TraceDescriptorMsg.create({ status: "complete", revision: "2" }), + }, + }), + envelope("4", { + oneofKind: "logAppended", + logAppended: { + runId: secondSummary.runId, + log: LogRecordDescriptorMsg.create({ sequence: "1", nodeId: "fetch" }), + }, + }), + envelope("5", { + oneofKind: "agentEventAppended", + agentEventAppended: { + runId: secondSummary.runId, + nodeId: "fetch", + event: AgentEventDescriptorMsg.create({ eventSequence: "1" }), + }, + }), + envelope("6", { + oneofKind: "runStatusChanged", + runStatusChanged: { + runId: secondSummary.runId, + status: "failed", + revision: "2", + startedAt: 1, + endedAt: 2, + }, + }), + ], + }); + + expect(state.runs[secondSummary.runId].status).toBe("failed"); + expect(state.selectedRun?.nodes).toEqual(original.selectedRun?.nodes); + expect(state.selectedRun?.summary?.status).toBe("running"); + expect(state.liveLogs).toEqual({}); + expect(state.liveEvents).toEqual({}); + }); + + it("orders and deduplicates one cross-step live descriptor tail per run", () => { + const state = projectionReducer(selectedState(), { + type: "envelopes", + envelopes: [ + envelope("2", { + oneofKind: "logAppended", + logAppended: { + runId: summary.runId, + log: LogRecordDescriptorMsg.create({ sequence: "3", nodeId: "fetch" }), + }, + }), + envelope("3", { + oneofKind: "logAppended", + logAppended: { + runId: summary.runId, + log: LogRecordDescriptorMsg.create({ sequence: "1", nodeId: "fetch" }), + }, + }), + envelope("4", { + oneofKind: "logAppended", + logAppended: { + runId: summary.runId, + log: LogRecordDescriptorMsg.create({ sequence: "2", nodeId: "validate" }), + }, + }), + envelope("5", { + oneofKind: "logAppended", + logAppended: { + runId: summary.runId, + log: LogRecordDescriptorMsg.create({ sequence: "2", nodeId: "validate" }), + }, + }), + ], + }); + + expect(state.liveLogs["run-1"].map((entry) => entry.sequence)).toEqual([ + "1", + "2", + "3", + ]); + }); + + it("bounds live log and event tails and records repair watermarks", () => { + const logEnvelopes = Array.from({ length: 260 }, (_, index) => + envelope(String(index + 2), { + oneofKind: "logAppended", + logAppended: { + runId: summary.runId, + log: LogRecordDescriptorMsg.create({ sequence: String(index + 1), nodeId: "fetch" }), + }, + }), + ); + const eventEnvelopes = Array.from({ length: 260 }, (_, index) => + envelope(String(index + 262), { + oneofKind: "agentEventAppended", + agentEventAppended: { + runId: summary.runId, + nodeId: "fetch", + event: AgentEventDescriptorMsg.create({ eventSequence: String(index + 1) }), + }, + }), + ); + + const state = projectionReducer(selectedState(), { + type: "envelopes", + envelopes: [...logEnvelopes, ...eventEnvelopes], + }); + + expect(state.liveLogs["run-1"]).toHaveLength(256); + expect(state.liveLogs["run-1"][0].sequence).toBe("5"); + expect(state.liveLogRepairWatermarks["run-1"]).toBe("4"); + expect(state.liveEvents["run-1:fetch"]).toHaveLength(256); + expect(state.liveEvents["run-1:fetch"][0].eventSequence).toBe("5"); + expect(state.liveEventRepairWatermarks["run-1:fetch"]).toBe("4"); + }); + + it("installs summary, nodes, and continuations from one atomic snapshot revision", () => { + const atomicSummary = RunSummaryMsg.create({ + ...summary, + status: "complete", + revision: "5", + }); + const atomicSnapshot = RunSnapshotMsg.create({ + operatorInstanceId: "operator-1", + asOfSequence: "5", + summary: atomicSummary, + nodes: [ + NodeSnapshotMsg.create({ + ...node, + status: "complete", + revision: "5", + eventPageToken: "events-r5", + }), + ], + topology, + logPageToken: "logs-r5", + }); + const previous = { + ...selectedState(), + liveLogs: { + "run-1": [LogRecordDescriptorMsg.create({ sequence: "2" })], + "run-2": [LogRecordDescriptorMsg.create({ sequence: "9" })], + }, + liveEvents: { + "run-1:fetch": [AgentEventDescriptorMsg.create({ eventSequence: "2" })], + }, + liveLogRepairWatermarks: { "run-1": "2", "run-2": "9" }, + liveEventRepairWatermarks: { "run-1:fetch": "2" }, + }; + + let state = projectionReducer(previous, { + type: "selectionReady", + runId: summary.runId, + snapshot: atomicSnapshot, + }); + state = projectionReducer(state, { + type: "envelopes", + envelopes: [ + envelope("2", { + oneofKind: "nodeStatusChanged", + nodeStatusChanged: { + runId: summary.runId, + nodeId: node.nodeId, + status: "running", + revision: "2", + startedAt: 1, + endedAt: 0, + }, + }), + envelope("3", { + oneofKind: "runStatusChanged", + runStatusChanged: { + runId: summary.runId, + status: "running", + revision: "2", + startedAt: 1, + endedAt: 0, + }, + }), + ], + }); + + expect(state.selectedRun).toBe(atomicSnapshot); + expect(state.selectedRun?.summary).toEqual(atomicSummary); + expect(state.selectedRun?.nodes[0]).toMatchObject({ + revision: "5", + eventPageToken: "events-r5", + }); + expect(state.selectedRun?.logPageToken).toBe("logs-r5"); + expect(state.liveLogs["run-1"]).toBeUndefined(); + expect(state.liveEvents["run-1:fetch"]).toBeUndefined(); + expect(state.liveLogRepairWatermarks).toEqual({ "run-2": "9" }); + expect(state.liveEventRepairWatermarks).toEqual({}); + }); + + it("rejects a snapshot overtaken by projection sequence or summary revision", () => { + const initial = projectionReducer(emptyProjection, { type: "baseline", baseline }); + let loading = projectionReducer(initial, { + type: "selectionLoading", + runId: summary.runId, + }); + loading = projectionReducer(loading, { + type: "envelopes", + envelopes: [ + envelope("2", { + oneofKind: "runStatusChanged", + runStatusChanged: { + runId: summary.runId, + status: "complete", + revision: "2", + startedAt: 1, + endedAt: 2, + }, + }), + ], + }); + + const sequenceStale = projectionReducer(loading, { + type: "selectionReady", + runId: summary.runId, + snapshot: snapshotFor(summary), + }); + const revisionStale = projectionReducer(loading, { + type: "selectionReady", + runId: summary.runId, + snapshot: RunSnapshotMsg.create({ + ...snapshotFor(summary), + asOfSequence: "2", + }), + }); + + expect(sequenceStale).toBe(loading); + expect(revisionStale).toBe(loading); + expect(loading.selectedRunStatus).toBe("loading"); + expect(loading.selectedRun).toBeUndefined(); + }); + + it("rejects epoch changes, sequence gaps, and reset notices", () => { + const state = projectionReducer(emptyProjection, { type: "baseline", baseline }); + const reset = OperatorUpdateEnvelope.create({ + operatorInstanceId: "operator-1", + payload: { + oneofKind: "resetRequired", + resetRequired: { historyFloor: "2", latestSequence: "8" }, + }, + }); + + expect(() => + projectionReducer(state, { type: "envelopes", envelopes: [envelope("2", undefined, "other")] }), + ).toThrow("epoch changed"); + expect(() => + projectionReducer(state, { type: "envelopes", envelopes: [envelope("3")] }), + ).toThrow("update gap"); + expect(() => + projectionReducer(state, { type: "envelopes", envelopes: [reset] }), + ).toThrow("structural reset"); + }); +}); + +describe("useOperatorProjection", () => { + it("cancels a superseded selected snapshot and ignores its stale result", async () => { + const first = deferred(); + const second = deferred(); + const signals: AbortSignal[] = []; + const getLatestRunSnapshot = vi.fn( + (runId: string, _operatorInstanceId: string, signal?: AbortSignal) => { + if (signal) signals.push(signal); + return runId === summary.runId ? first.promise : second.promise; + }, + ); + const api = createApi({ + loadBaseline: async () => ({ ...baseline, runs: [summary, secondSummary] }), + getLatestRunSnapshot, + }); + const { result } = renderHook(() => useOperatorProjection(api)); + await waitFor(() => expect(result.current.state.connection).toBe("live")); + + act(() => { + void result.current.selectRun(summary.runId); + }); + await waitFor(() => expect(result.current.state.selectedRunStatus).toBe("loading")); + act(() => { + void result.current.selectRun(secondSummary.runId); + }); + + expect(signals[0].aborted).toBe(true); + act(() => second.resolve(snapshotFor(secondSummary))); + await waitFor(() => expect(result.current.state.selectedRunStatus).toBe("ready")); + + act(() => first.resolve(snapshotFor(summary))); + await act(async () => { + await first.promise; + }); + expect(result.current.state.selectedRunId).toBe(secondSummary.runId); + expect(result.current.state.selectedRun?.summary?.runId).toBe(secondSummary.runId); + }); + + it("aborts a selected snapshot on baseline replacement and ignores its stale result", async () => { + const releaseReset = deferred(); + const stale = deferred(); + const selectionSignals: AbortSignal[] = []; + const replacement: StructuralBaseline = { + catalog: CatalogSnapshotMsg.create({ + ...baseline.catalog, + asOfSequence: "8", + revision: "2", + }), + asOfSequence: "8", + runs: [summary], + }; + const loadBaseline = vi + .fn<(signal?: AbortSignal) => Promise>() + .mockResolvedValueOnce(baseline) + .mockResolvedValue(replacement); + let streamCount = 0; + const streamUpdates = vi.fn( + (_operatorInstanceId: string, _afterSequence: string, signal?: AbortSignal) => { + streamCount += 1; + if (streamCount > 1) return idleUpdates(signal); + return (async function* () { + await releaseReset.promise; + yield OperatorUpdateEnvelope.create({ + operatorInstanceId: "operator-1", + payload: { + oneofKind: "resetRequired", + resetRequired: { historyFloor: "2", latestSequence: "8" }, + }, + }); + })(); + }, + ); + const api = createApi({ + loadBaseline, + streamUpdates, + getLatestRunSnapshot: (_runId, _operatorInstanceId, signal) => { + if (signal) selectionSignals.push(signal); + return stale.promise; + }, + }); + const { result } = renderHook(() => useOperatorProjection(api)); + await waitFor(() => expect(result.current.state.connection).toBe("live")); + + act(() => { + void result.current.selectRun(summary.runId); + }); + await waitFor(() => expect(selectionSignals).toHaveLength(1)); + act(() => releaseReset.resolve()); + await waitFor(() => expect(result.current.state.sequence).toBe("8")); + + expect(selectionSignals[0].aborted).toBe(true); + expect(result.current.state.selectedRunStatus).toBe("idle"); + act(() => stale.resolve(snapshotFor(summary))); + await act(async () => { + await stale.promise; + }); + expect(result.current.state.selectedRunId).toBeUndefined(); + expect(result.current.state.selectedRun).toBeUndefined(); + }); + + it("applies contiguous stream envelopes in frame batches of at most 256", async () => { + const callbacks: FrameRequestCallback[] = []; + let frameId = 0; + vi.spyOn(window, "requestAnimationFrame").mockImplementation((callback) => { + callbacks.push(callback); + frameId += 1; + return frameId; + }); + vi.spyOn(window, "cancelAnimationFrame").mockImplementation(() => undefined); + let produced = false; + const streamUpdates = vi.fn( + (_operatorInstanceId: string, _afterSequence: string, signal?: AbortSignal) => + (async function* () { + for (let sequence = 2; sequence <= 601; sequence += 1) { + yield envelope(String(sequence)); + } + produced = true; + yield* idleUpdates(signal); + })(), + ); + const api = createApi({ streamUpdates }); + const { result } = renderHook(() => useOperatorProjection(api)); + + await waitFor(() => expect(produced).toBe(true)); + expect(callbacks).toHaveLength(1); + act(() => callbacks.shift()?.(0)); + expect(result.current.state.sequence).toBe("257"); + expect(callbacks).toHaveLength(1); + act(() => callbacks.shift()?.(1)); + expect(result.current.state.sequence).toBe("513"); + expect(callbacks).toHaveLength(1); + act(() => callbacks.shift()?.(2)); + expect(result.current.state.sequence).toBe("601"); + expect(callbacks).toHaveLength(0); + }); + + it("aborts an overflowing pending queue and reconciles from a new baseline", async () => { + vi.spyOn(window, "requestAnimationFrame").mockImplementation(() => 1); + const cancelAnimationFrame = vi + .spyOn(window, "cancelAnimationFrame") + .mockImplementation(() => undefined); + const replacement: StructuralBaseline = { + catalog: CatalogSnapshotMsg.create({ + ...baseline.catalog, + asOfSequence: "2000", + revision: "2", + }), + asOfSequence: "2000", + runs: [summary], + }; + const loadBaseline = vi + .fn<(signal?: AbortSignal) => Promise>() + .mockResolvedValueOnce(baseline) + .mockResolvedValue(replacement); + const streamSignals: AbortSignal[] = []; + let streamCount = 0; + const streamUpdates = vi.fn( + (_operatorInstanceId: string, _afterSequence: string, signal?: AbortSignal) => { + if (signal) streamSignals.push(signal); + streamCount += 1; + if (streamCount > 1) return idleUpdates(signal); + return (async function* () { + for (let sequence = 2; sequence <= 1026; sequence += 1) { + yield envelope(String(sequence)); + } + })(); + }, + ); + const api = createApi({ loadBaseline, streamUpdates }); + const { result } = renderHook(() => useOperatorProjection(api)); + + await waitFor(() => expect(result.current.state.sequence).toBe("2000")); + expect(loadBaseline).toHaveBeenCalledTimes(2); + expect(streamSignals[0].aborted).toBe(true); + expect(cancelAnimationFrame).toHaveBeenCalled(); + }); + + it.each([ + ["epoch change", envelope("2", undefined, "operator-2")], + ["sequence gap", envelope("3")], + [ + "reset notice", + OperatorUpdateEnvelope.create({ + operatorInstanceId: "operator-1", + payload: { + oneofKind: "resetRequired", + resetRequired: { historyFloor: "2", latestSequence: "8" }, + }, + }), + ], + ])("aborts and reconciles after a stream %s", async (_name, invalidEnvelope) => { + const replacement: StructuralBaseline = { + catalog: CatalogSnapshotMsg.create({ + ...baseline.catalog, + asOfSequence: "8", + revision: "2", + }), + asOfSequence: "8", + runs: [summary], + }; + const loadBaseline = vi + .fn<(signal?: AbortSignal) => Promise>() + .mockResolvedValueOnce(baseline) + .mockResolvedValue(replacement); + const streamSignals: AbortSignal[] = []; + let streamCount = 0; + const streamUpdates = vi.fn( + (_operatorInstanceId: string, _afterSequence: string, signal?: AbortSignal) => { + if (signal) streamSignals.push(signal); + streamCount += 1; + if (streamCount > 1) return idleUpdates(signal); + return (async function* () { + yield invalidEnvelope; + })(); + }, + ); + const api = createApi({ loadBaseline, streamUpdates }); + const { result } = renderHook(() => useOperatorProjection(api)); + + await waitFor(() => expect(result.current.state.sequence).toBe("8")); + expect(loadBaseline).toHaveBeenCalledTimes(2); + expect(streamSignals[0].aborted).toBe(true); + }); + + it("retries instead of committing an N snapshot after N+1 projection state", async () => { + const releaseUpdate = deferred(); + const stale = deferred(); + const current = deferred(); + const getLatestRunSnapshot = vi + .fn() + .mockImplementationOnce(() => stale.promise) + .mockImplementationOnce(() => current.promise); + const api = createApi({ + getLatestRunSnapshot, + streamUpdates: (_operatorInstanceId, _afterSequence, signal) => + (async function* () { + await releaseUpdate.promise; + yield envelope("2", { + oneofKind: "nodeStatusChanged", + nodeStatusChanged: { + runId: summary.runId, + nodeId: node.nodeId, + status: "complete", + revision: "2", + startedAt: 1, + endedAt: 2, + }, + }); + yield* idleUpdates(signal); + })(), + }); + const { result } = renderHook(() => useOperatorProjection(api)); + await waitFor(() => expect(result.current.state.connection).toBe("live")); + + act(() => { + void result.current.selectRun(summary.runId); + }); + await waitFor(() => expect(getLatestRunSnapshot).toHaveBeenCalledTimes(1)); + act(() => releaseUpdate.resolve()); + await waitFor(() => expect(result.current.state.sequence).toBe("2")); + act(() => stale.resolve(snapshotFor(summary))); + + await waitFor(() => expect(getLatestRunSnapshot).toHaveBeenCalledTimes(2)); + expect(result.current.state.selectedRunStatus).toBe("loading"); + expect(result.current.state.selectedRun).toBeUndefined(); + + act(() => + current.resolve( + RunSnapshotMsg.create({ + ...snapshotFor(summary), + asOfSequence: "2", + nodes: [NodeSnapshotMsg.create({ ...node, status: "complete", revision: "2" })], + }), + ), + ); + await waitFor(() => expect(result.current.state.selectedRunStatus).toBe("ready")); + expect(result.current.state.selectedRun?.nodes[0]).toMatchObject({ + status: "complete", + revision: "2", + }); + }); + + it("refreshes exactly once after overflow and replaces the gap with a fresh snapshot", async () => { + const startUpdates = deferred(); + const repaired = deferred(); + const getLatestRunSnapshot = vi + .fn() + .mockResolvedValueOnce(snapshotFor(summary)) + .mockImplementationOnce(() => repaired.promise); + const api = createApi({ + getLatestRunSnapshot, + streamUpdates: (_operatorInstanceId, _afterSequence, signal) => + (async function* () { + await startUpdates.promise; + for (let index = 1; index <= 257; index += 1) { + yield envelope(String(index + 1), { + oneofKind: "logAppended", + logAppended: { + runId: summary.runId, + log: LogRecordDescriptorMsg.create({ + sequence: String(index), + nodeId: node.nodeId, + }), + }, + }); + } + yield* idleUpdates(signal); + })(), + }); + const { result } = renderHook(() => useOperatorProjection(api)); + await waitFor(() => expect(result.current.state.connection).toBe("live")); + act(() => { + void result.current.selectRun(summary.runId); + }); + await waitFor(() => expect(result.current.state.selectedRunStatus).toBe("ready")); + + act(() => startUpdates.resolve()); + await waitFor(() => expect(getLatestRunSnapshot).toHaveBeenCalledTimes(2)); + expect(result.current.state.liveLogs["run-1"]).toHaveLength(256); + expect(result.current.state.liveLogRepairWatermarks["run-1"]).toBe("1"); + + act(() => + repaired.resolve( + RunSnapshotMsg.create({ + ...snapshotFor(summary), + asOfSequence: "258", + logPageToken: "logs-through-257", + }), + ), + ); + await waitFor(() => + expect(result.current.state.selectedRun?.logPageToken).toBe("logs-through-257"), + ); + expect(getLatestRunSnapshot).toHaveBeenCalledTimes(2); + expect(result.current.state.liveLogs).toEqual({}); + expect(result.current.state.liveLogRepairWatermarks).toEqual({}); + }); + + it("aborts an obsolete overflow refresh and suppresses its stale snapshot", async () => { + const startUpdates = deferred(); + const appendAgain = deferred(); + const obsolete = deferred(); + const replacement = deferred(); + const repairSignals: AbortSignal[] = []; + let request = 0; + const getLatestRunSnapshot = vi.fn( + (_runId, _operatorInstanceId, signal) => { + request += 1; + if (request === 1) return Promise.resolve(snapshotFor(summary)); + if (signal) repairSignals.push(signal); + return request === 2 ? obsolete.promise : replacement.promise; + }, + ); + const api = createApi({ + getLatestRunSnapshot, + streamUpdates: (_operatorInstanceId, _afterSequence, signal) => + (async function* () { + await startUpdates.promise; + for (let index = 1; index <= 257; index += 1) { + yield envelope(String(index + 1), { + oneofKind: "logAppended", + logAppended: { + runId: summary.runId, + log: LogRecordDescriptorMsg.create({ + sequence: String(index), + nodeId: node.nodeId, + }), + }, + }); + } + await appendAgain.promise; + yield envelope("259", { + oneofKind: "logAppended", + logAppended: { + runId: summary.runId, + log: LogRecordDescriptorMsg.create({ sequence: "258", nodeId: node.nodeId }), + }, + }); + yield* idleUpdates(signal); + })(), + }); + const { result } = renderHook(() => useOperatorProjection(api)); + await waitFor(() => expect(result.current.state.connection).toBe("live")); + act(() => { + void result.current.selectRun(summary.runId); + }); + await waitFor(() => expect(result.current.state.selectedRunStatus).toBe("ready")); + + act(() => startUpdates.resolve()); + await waitFor(() => expect(getLatestRunSnapshot).toHaveBeenCalledTimes(2)); + act(() => appendAgain.resolve()); + await waitFor(() => expect(getLatestRunSnapshot).toHaveBeenCalledTimes(3)); + expect(repairSignals[0].aborted).toBe(true); + + act(() => + replacement.resolve( + RunSnapshotMsg.create({ + ...snapshotFor(summary), + asOfSequence: "259", + logPageToken: "replacement-token", + }), + ), + ); + await waitFor(() => + expect(result.current.state.selectedRun?.logPageToken).toBe("replacement-token"), + ); + act(() => + obsolete.resolve( + RunSnapshotMsg.create({ + ...snapshotFor(summary), + asOfSequence: "258", + logPageToken: "obsolete-token", + }), + ), + ); + await act(async () => { + await obsolete.promise; + }); + + expect(result.current.state.selectedRun?.logPageToken).toBe("replacement-token"); + expect(result.current.state.liveLogs).toEqual({}); + expect(result.current.state.liveLogRepairWatermarks).toEqual({}); + }); + + it("aborts stream and selected snapshot work on cleanup", async () => { + let streamSignal: AbortSignal | undefined; + let selectionSignal: AbortSignal | undefined; + const selected = deferred(); + const api = createApi({ + streamUpdates: (_operatorInstanceId, _afterSequence, signal) => { + streamSignal = signal; + return idleUpdates(signal); + }, + getLatestRunSnapshot: (_runId, _operatorInstanceId, signal) => { + selectionSignal = signal; + return selected.promise; + }, + }); + const { result, unmount } = renderHook(() => useOperatorProjection(api)); + await waitFor(() => expect(result.current.state.connection).toBe("live")); + act(() => { + void result.current.selectRun(summary.runId); + }); + await waitFor(() => expect(result.current.state.selectedRunStatus).toBe("loading")); + + unmount(); + + expect(streamSignal?.aborted).toBe(true); + expect(selectionSignal?.aborted).toBe(true); + }); +}); diff --git a/web/operator/src/state.ts b/web/operator/src/state.ts new file mode 100644 index 0000000..1704d5e --- /dev/null +++ b/web/operator/src/state.ts @@ -0,0 +1,609 @@ +import { useCallback, useEffect, useReducer, useRef } from "react"; + +import type { OperatorApi, StructuralBaseline } from "./api"; +import type { + AgentEventDescriptorMsg, + CatalogSnapshotMsg, + LogRecordDescriptorMsg, + OperatorUpdateEnvelope, + RunSnapshotMsg, + RunSummaryMsg, +} from "./generated/operator"; + +const MAX_PENDING_ENVELOPES = 1024; +const MAX_ENVELOPES_PER_FRAME = 256; +const MAX_LIVE_DESCRIPTORS = 256; + +export type SelectedRunStatus = "idle" | "loading" | "ready" | "error"; + +export interface OperatorProjection { + catalog?: CatalogSnapshotMsg; + runs: Record; + selectedRunId?: string; + selectedRun?: RunSnapshotMsg; + selectedRunStatus: SelectedRunStatus; + selectedRunError?: string; + liveEvents: Record; + liveLogs: Record; + liveEventRepairWatermarks: Record; + liveLogRepairWatermarks: Record; + operatorInstanceId: string; + sequence: string; + connection: "connecting" | "live" | "reconnecting"; + error?: string; + action?: { kind: "start" | "cancel"; target: string }; +} + +type ProjectionAction = + | { type: "baseline"; baseline: StructuralBaseline } + | { type: "envelopes"; envelopes: OperatorUpdateEnvelope[] } + | { type: "connection"; connection: OperatorProjection["connection"]; error?: string } + | { type: "action"; action?: OperatorProjection["action"] } + | { type: "selectionLoading"; runId: string } + | { type: "selectionReady"; runId: string; snapshot: RunSnapshotMsg } + | { type: "selectionError"; runId: string; error: string } + | { type: "selectionCleared" }; + +export const emptyProjection: OperatorProjection = { + runs: {}, + selectedRunStatus: "idle", + liveEvents: {}, + liveLogs: {}, + liveEventRepairWatermarks: {}, + liveLogRepairWatermarks: {}, + operatorInstanceId: "", + sequence: "0", + connection: "connecting", +}; + +interface BoundedAppend { + items: T[]; + droppedThrough?: string; +} + +function appendBounded( + current: T[], + item: T, + sequenceOf: (value: T) => string, +): BoundedAppend { + const sequence = BigInt(sequenceOf(item)); + if (current.some((value) => BigInt(sequenceOf(value)) === sequence)) return { items: current }; + + let insertion = current.length; + while (insertion > 0 && BigInt(sequenceOf(current[insertion - 1])) > sequence) insertion -= 1; + const ordered = [...current.slice(0, insertion), item, ...current.slice(insertion)]; + if (ordered.length <= MAX_LIVE_DESCRIPTORS) return { items: ordered }; + + const dropped = ordered.length - MAX_LIVE_DESCRIPTORS; + return { + items: ordered.slice(dropped), + droppedThrough: sequenceOf(ordered[dropped - 1]), + }; +} + +function laterWatermark(current: string | undefined, candidate: string): string { + return current === undefined || BigInt(candidate) > BigInt(current) ? candidate : current; +} + +function snapshotCanCommit( + state: OperatorProjection, + runId: string, + snapshot: RunSnapshotMsg, +): boolean { + if ( + snapshot.operatorInstanceId !== state.operatorInstanceId || + snapshot.summary?.runId !== runId || + BigInt(snapshot.asOfSequence) < BigInt(state.sequence) + ) { + return false; + } + const projectedSummary = state.runs[runId]; + return ( + projectedSummary === undefined || + BigInt(snapshot.summary.revision) >= BigInt(projectedSummary.revision) + ); +} + +function withoutRunBuckets( + buckets: Record, + runId: string, +): Record { + const prefix = `${runId}:`; + return Object.fromEntries(Object.entries(buckets).filter(([key]) => !key.startsWith(prefix))); +} + +function withoutKey(buckets: Record, key: string): Record { + return Object.fromEntries(Object.entries(buckets).filter(([candidate]) => candidate !== key)); +} + +function applyEnvelope( + state: OperatorProjection, + envelope: OperatorUpdateEnvelope, +): OperatorProjection { + if (envelope.operatorInstanceId !== state.operatorInstanceId) { + throw new Error("Operator epoch changed"); + } + if (envelope.payload.oneofKind !== "update") { + throw new Error("Operator requested a structural reset"); + } + const update = envelope.payload.update; + if (BigInt(update.sequence) !== BigInt(state.sequence) + 1n) { + throw new Error(`Operator update gap after sequence ${state.sequence}`); + } + + const next: OperatorProjection = { ...state, sequence: update.sequence, error: undefined }; + const change = update.change; + if (change.oneofKind === "catalogReplaced") { + if (change.catalogReplaced.catalog) next.catalog = change.catalogReplaced.catalog; + return next; + } + if (change.oneofKind === "runCreated" && change.runCreated.summary) { + const summary = change.runCreated.summary; + next.runs = { ...state.runs, [summary.runId]: summary }; + return next; + } + + const runId = + change.oneofKind === "runStatusChanged" + ? change.runStatusChanged.runId + : change.oneofKind === "nodeStatusChanged" + ? change.nodeStatusChanged.runId + : change.oneofKind === "logAppended" + ? change.logAppended.runId + : change.oneofKind === "agentEventAppended" + ? change.agentEventAppended.runId + : change.oneofKind === "traceFinalized" + ? change.traceFinalized.runId + : ""; + const selectedSnapshot = state.selectedRunId === runId ? state.selectedRun : undefined; + const selected = + selectedSnapshot && BigInt(update.sequence) > BigInt(selectedSnapshot.asOfSequence) + ? selectedSnapshot + : undefined; + + if (change.oneofKind === "runStatusChanged") { + const changed = change.runStatusChanged; + const summary = state.runs[runId]; + if (summary) { + next.runs = { + ...state.runs, + [runId]: { + ...summary, + status: changed.status, + startedAt: changed.startedAt, + endedAt: changed.endedAt, + revision: changed.revision, + }, + }; + } + if (selected?.summary) { + next.selectedRun = { + ...selected, + summary: { + ...selected.summary, + status: changed.status, + startedAt: changed.startedAt, + endedAt: changed.endedAt, + revision: changed.revision, + }, + }; + } + } else if (change.oneofKind === "nodeStatusChanged" && selected) { + const changed = change.nodeStatusChanged; + next.selectedRun = { + ...selected, + nodes: selected.nodes.map((node) => + node.nodeId === changed.nodeId + ? { + ...node, + status: changed.status, + startedAt: changed.startedAt, + endedAt: changed.endedAt, + revision: changed.revision, + error: changed.error, + } + : node, + ), + }; + } else if ( + change.oneofKind === "logAppended" && + state.selectedRunId === runId && + (selectedSnapshot === undefined || + BigInt(update.sequence) > BigInt(selectedSnapshot.asOfSequence)) && + change.logAppended.log + ) { + const log = change.logAppended.log; + const key = runId; + const appended = appendBounded(state.liveLogs[key] ?? [], log, (value) => value.sequence); + if (appended.items !== state.liveLogs[key]) { + next.liveLogs = { ...state.liveLogs, [key]: appended.items }; + } + if (appended.droppedThrough !== undefined) { + next.liveLogRepairWatermarks = { + ...state.liveLogRepairWatermarks, + [key]: laterWatermark(state.liveLogRepairWatermarks[key], appended.droppedThrough), + }; + } + } else if ( + change.oneofKind === "agentEventAppended" && + state.selectedRunId === runId && + (selectedSnapshot === undefined || + BigInt(update.sequence) > BigInt(selectedSnapshot.asOfSequence)) && + change.agentEventAppended.event + ) { + const event = change.agentEventAppended.event; + const key = `${runId}:${change.agentEventAppended.nodeId}`; + const appended = appendBounded( + state.liveEvents[key] ?? [], + event, + (value) => value.eventSequence, + ); + if (appended.items !== state.liveEvents[key]) { + next.liveEvents = { ...state.liveEvents, [key]: appended.items }; + } + if (appended.droppedThrough !== undefined) { + next.liveEventRepairWatermarks = { + ...state.liveEventRepairWatermarks, + [key]: laterWatermark(state.liveEventRepairWatermarks[key], appended.droppedThrough), + }; + } + } else if (change.oneofKind === "traceFinalized" && selected && change.traceFinalized.trace) { + next.selectedRun = { + ...selected, + nodes: selected.nodes.map((node) => + node.nodeId === change.traceFinalized.nodeId + ? { ...node, trace: change.traceFinalized.trace } + : node, + ), + }; + } + return next; +} + +export function projectionReducer( + state: OperatorProjection, + action: ProjectionAction, +): OperatorProjection { + if (action.type === "baseline") { + return { + ...emptyProjection, + catalog: action.baseline.catalog, + runs: Object.fromEntries(action.baseline.runs.map((run) => [run.runId, run])), + operatorInstanceId: action.baseline.catalog.operatorInstanceId, + sequence: action.baseline.asOfSequence, + connection: "live", + }; + } + if (action.type === "connection") { + return { ...state, connection: action.connection, error: action.error }; + } + if (action.type === "action") return { ...state, action: action.action }; + if (action.type === "selectionLoading") { + return { + ...state, + selectedRunId: action.runId, + selectedRun: undefined, + selectedRunStatus: "loading", + selectedRunError: undefined, + liveEvents: {}, + liveLogs: {}, + liveEventRepairWatermarks: {}, + liveLogRepairWatermarks: {}, + }; + } + if (action.type === "selectionReady") { + if ( + state.selectedRunId !== action.runId || + !snapshotCanCommit(state, action.runId, action.snapshot) + ) { + return state; + } + return { + ...state, + selectedRunId: action.runId, + selectedRun: action.snapshot, + selectedRunStatus: "ready", + selectedRunError: undefined, + liveEvents: withoutRunBuckets(state.liveEvents, action.runId), + liveLogs: withoutKey(state.liveLogs, action.runId), + liveEventRepairWatermarks: withoutRunBuckets( + state.liveEventRepairWatermarks, + action.runId, + ), + liveLogRepairWatermarks: withoutKey(state.liveLogRepairWatermarks, action.runId), + }; + } + if (action.type === "selectionError") { + return { + ...state, + selectedRunId: action.runId, + selectedRun: undefined, + selectedRunStatus: "error", + selectedRunError: action.error, + }; + } + if (action.type === "selectionCleared") { + return { + ...state, + selectedRunId: undefined, + selectedRun: undefined, + selectedRunStatus: "idle", + selectedRunError: undefined, + liveEvents: {}, + liveLogs: {}, + liveEventRepairWatermarks: {}, + liveLogRepairWatermarks: {}, + }; + } + + let next = state; + for (const envelope of action.envelopes) next = applyEnvelope(next, envelope); + return next; +} + +export function useOperatorProjection(api: OperatorApi) { + const [state, dispatch] = useReducer(projectionReducer, emptyProjection); + const stateRef = useRef(state); + stateRef.current = state; + const projectionCursor = useRef({ + operatorInstanceId: state.operatorInstanceId, + sequence: state.sequence, + }); + if ( + projectionCursor.current.operatorInstanceId !== state.operatorInstanceId || + BigInt(state.sequence) > BigInt(projectionCursor.current.sequence) + ) { + projectionCursor.current = { + operatorInstanceId: state.operatorInstanceId, + sequence: state.sequence, + }; + } + + const cycleController = useRef(undefined); + const selectionController = useRef(undefined); + const selectionGeneration = useRef(0); + const pendingFrame = useRef(undefined); + const retryTimer = useRef(undefined); + const wakeRetry = useRef<(() => void) | undefined>(undefined); + + const abortSelection = useCallback(() => { + selectionGeneration.current += 1; + selectionController.current?.abort(); + selectionController.current = undefined; + }, []); + + const reconcile = useCallback(() => { + cycleController.current?.abort(); + wakeRetry.current?.(); + }, []); + + useEffect(() => { + const lifecycle = new AbortController(); + let retryMilliseconds = 250; + + const waitForRetry = (milliseconds: number) => + new Promise((resolve) => { + const finish = () => { + if (retryTimer.current !== undefined) window.clearTimeout(retryTimer.current); + retryTimer.current = undefined; + if (wakeRetry.current === finish) wakeRetry.current = undefined; + resolve(); + }; + wakeRetry.current = finish; + retryTimer.current = window.setTimeout(finish, milliseconds); + }); + + const run = async () => { + while (!lifecycle.signal.aborted) { + const cycle = new AbortController(); + cycleController.current = cycle; + let pending: OperatorUpdateEnvelope[] = []; + let retryAfterCycle = 0; + + const clearPending = () => { + pending = []; + if (pendingFrame.current !== undefined) { + window.cancelAnimationFrame(pendingFrame.current); + pendingFrame.current = undefined; + } + }; + const scheduleFrame = () => { + if (pendingFrame.current !== undefined || cycle.signal.aborted) return; + pendingFrame.current = window.requestAnimationFrame(() => { + pendingFrame.current = undefined; + if (cycle.signal.aborted) { + pending = []; + return; + } + const envelopes = pending.splice(0, MAX_ENVELOPES_PER_FRAME); + if (envelopes.length > 0) { + const latest = envelopes[envelopes.length - 1]; + if (latest.payload.oneofKind === "update") { + projectionCursor.current = { + operatorInstanceId: latest.operatorInstanceId, + sequence: latest.payload.update.sequence, + }; + } + dispatch({ type: "envelopes", envelopes }); + } + if (pending.length > 0) scheduleFrame(); + }); + }; + + try { + dispatch({ type: "connection", connection: "connecting" }); + const baseline = await api.loadBaseline(cycle.signal); + if (cycle.signal.aborted || lifecycle.signal.aborted) continue; + abortSelection(); + projectionCursor.current = { + operatorInstanceId: baseline.catalog.operatorInstanceId, + sequence: baseline.asOfSequence, + }; + dispatch({ type: "baseline", baseline }); + retryMilliseconds = 250; + + let expectedSequence = baseline.asOfSequence; + for await (const envelope of api.streamUpdates( + baseline.catalog.operatorInstanceId, + expectedSequence, + cycle.signal, + )) { + if (cycle.signal.aborted || lifecycle.signal.aborted) break; + if ( + envelope.operatorInstanceId !== baseline.catalog.operatorInstanceId || + envelope.payload.oneofKind !== "update" || + BigInt(envelope.payload.update.sequence) !== BigInt(expectedSequence) + 1n || + pending.length >= MAX_PENDING_ENVELOPES + ) { + cycle.abort(); + break; + } + pending.push(envelope); + expectedSequence = envelope.payload.update.sequence; + scheduleFrame(); + } + clearPending(); + if (!lifecycle.signal.aborted) { + dispatch({ type: "connection", connection: "reconnecting" }); + } + } catch (error) { + clearPending(); + if (!lifecycle.signal.aborted && !cycle.signal.aborted) { + dispatch({ + type: "connection", + connection: "reconnecting", + error: error instanceof Error ? error.message : "Operator connection failed", + }); + retryAfterCycle = retryMilliseconds; + retryMilliseconds = Math.min(retryMilliseconds * 2, 4000); + } + } finally { + clearPending(); + cycle.abort(); + if (cycleController.current === cycle) cycleController.current = undefined; + } + + if (retryAfterCycle > 0 && !lifecycle.signal.aborted) { + await waitForRetry(retryAfterCycle); + } + } + }; + + void run(); + return () => { + lifecycle.abort(); + cycleController.current?.abort(); + if (pendingFrame.current !== undefined) { + window.cancelAnimationFrame(pendingFrame.current); + pendingFrame.current = undefined; + } + wakeRetry.current?.(); + abortSelection(); + }; + }, [abortSelection, api]); + + const loadSelectedRun = useCallback( + async (runId: string, showLoading: boolean) => { + abortSelection(); + const generation = selectionGeneration.current; + const controller = new AbortController(); + selectionController.current = controller; + const operatorInstanceId = stateRef.current.operatorInstanceId; + if (showLoading) dispatch({ type: "selectionLoading", runId }); + try { + while (!controller.signal.aborted && selectionGeneration.current === generation) { + const snapshot = await api.getLatestRunSnapshot( + runId, + operatorInstanceId, + controller.signal, + ); + if ( + controller.signal.aborted || + selectionGeneration.current !== generation || + stateRef.current.operatorInstanceId !== operatorInstanceId + ) { + return; + } + if ( + projectionCursor.current.operatorInstanceId !== operatorInstanceId || + BigInt(snapshot.asOfSequence) < BigInt(projectionCursor.current.sequence) + ) { + continue; + } + if (!snapshotCanCommit(stateRef.current, runId, snapshot)) continue; + dispatch({ type: "selectionReady", runId, snapshot }); + return; + } + } catch (error) { + if (controller.signal.aborted || selectionGeneration.current !== generation) return; + if (showLoading) { + dispatch({ + type: "selectionError", + runId, + error: error instanceof Error ? error.message : "Run snapshot failed", + }); + } + } finally { + if (selectionGeneration.current === generation) selectionController.current = undefined; + } + }, + [abortSelection, api], + ); + + const selectRun = useCallback( + async (runId?: string) => { + if (runId === undefined) { + abortSelection(); + dispatch({ type: "selectionCleared" }); + return; + } + await loadSelectedRun(runId, true); + }, + [abortSelection, loadSelectedRun], + ); + + const selectedRunId = state.selectedRunId; + const repairWatermark = + selectedRunId && state.selectedRunStatus === "ready" + ? [ + ...Object.entries(state.liveEventRepairWatermarks) + .filter(([key]) => key.startsWith(`${selectedRunId}:`)) + .sort(([left], [right]) => left.localeCompare(right)) + .map(([key, watermark]) => `${key}:${watermark}`), + ...(state.liveLogRepairWatermarks[selectedRunId] + ? [`${selectedRunId}:${state.liveLogRepairWatermarks[selectedRunId]}`] + : []), + ].join("|") + : ""; + + useEffect(() => { + if (!selectedRunId || !repairWatermark) return; + void loadSelectedRun(selectedRunId, false); + }, [loadSelectedRun, repairWatermark, selectedRunId]); + + const startRun = useCallback( + async (workflowSelector: string, input?: Record) => { + dispatch({ type: "action", action: { kind: "start", target: workflowSelector } }); + try { + return await api.startRun(workflowSelector, input); + } finally { + dispatch({ type: "action", action: undefined }); + } + }, + [api], + ); + + const cancelRun = useCallback( + async (runId: string) => { + dispatch({ type: "action", action: { kind: "cancel", target: runId } }); + try { + await api.cancelRun(runId); + } finally { + dispatch({ type: "action", action: undefined }); + } + }, + [api], + ); + + return { state, reconcile, startRun, cancelRun, selectRun }; +} diff --git a/web/operator/src/style.css b/web/operator/src/style.css new file mode 100644 index 0000000..b0ae0c5 --- /dev/null +++ b/web/operator/src/style.css @@ -0,0 +1,142 @@ +@import "tailwindcss"; + +@theme { + --color-ink: #17211c; + --color-canvas: #f6f8f7; + --color-panel: #ffffff; + --color-line: #dfe4e1; + --color-muted: #68746e; + --color-acid: #2563eb; + --color-mint: #16805d; + --color-amber: #a15c00; + --color-danger: #c43d36; + --color-secondary: #55615b; + --color-success: var(--color-green-500); + --color-failed: var(--color-red-500); + --color-agent: var(--color-violet-500); + --font-sans: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; + --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; +} + +@keyframes gradientRotate { + 0% { + background-position: 100% 100%; + } + + 50% { + background-position: 50% 100%; + } + + 100% { + background-position: 100% 100%; + } +} + +/* Animated gradient border for currently running workflow nodes. */ + +.gradient-animate { + border-color: transparent !important; + background: + linear-gradient(var(--color-panel), var(--color-panel)) padding-box, + linear-gradient( + 315deg, + hsl(163 100% 74%), + hsl(238 100% 63%) 68%, + hsl(163 100% 74%) + ) border-box !important; + background-size: 100% 100%, 200% 200% !important; + animation: gradientRotate 10s ease infinite; + transition: background 0.5s ease; +} + +@media (prefers-reduced-motion: reduce) { + .gradient-animate { + animation: none; + } +} + +@layer components { + .node-card { + transition: + border-color 150ms ease-out, + box-shadow 150ms ease-out, + min-height 200ms ease-out, + padding 200ms ease-out, + transform 150ms ease-out; + } + + .node-header, + .node-title, + .node-card-meta, + .node-card-details { + transition: + max-height 200ms ease-out, + opacity 150ms ease-out, + padding 200ms ease-out, + border-color 200ms ease-out, + transform 200ms ease-out, + font-size 200ms ease-out; + } + + .node-card-meta { + max-height: 3rem; + opacity: 1; + } + + .node-card-details { + max-height: 2000px; + opacity: 1; + } + + .node-card--compact { + min-height: 100px; + justify-content: center; + gap: 0; + } + + .node-card--compact .node-header { + min-height: 0; + align-items: center; + justify-content: center; + gap: 0; + padding-right: 0; + text-align: center; + } + + .node-card--compact .node-card-meta { + max-height: 0; + opacity: 0; + pointer-events: none; + } + + .node-card--compact .node-card-details { + min-height: 0; + max-height: 0; + gap: 0; + border-top-color: transparent; + padding-top: 0; + opacity: 0; + pointer-events: none; + } + + .node-card--compact .node-title { + display: -webkit-box; + max-width: 100%; + overflow: hidden; + overflow-wrap: anywhere; + text-align: center; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + transform: none; + } + + @media (prefers-reduced-motion: reduce) { + .node-card, + .node-header, + .node-title, + .node-card-meta, + .node-card-details { + transition: none; + } + } +} \ No newline at end of file diff --git a/web/operator/src/test/setup.ts b/web/operator/src/test/setup.ts new file mode 100644 index 0000000..24cf21a --- /dev/null +++ b/web/operator/src/test/setup.ts @@ -0,0 +1,82 @@ +import { cleanup } from "@testing-library/react"; +import { afterEach } from "vitest"; +import "@testing-library/jest-dom/vitest"; + +const viewportGeometry = [ + { selector: ".explorer", width: 280, height: 800 }, + { selector: ".turn-list", width: 640, height: 220 }, + { selector: ".log-list", width: 640, height: 220 }, +] as const; + +function geometryFor(element: Element) { + return viewportGeometry.find(({ selector }) => element.matches(selector)); +} + +const nativeGetBoundingClientRect = Element.prototype.getBoundingClientRect; +Element.prototype.getBoundingClientRect = function getBoundingClientRect() { + const geometry = geometryFor(this); + return geometry + ? new DOMRect(0, 0, geometry.width, geometry.height) + : nativeGetBoundingClientRect.call(this); +}; + +for (const [property, dimension] of [ + ["clientWidth", "width"], + ["clientHeight", "height"], + ["offsetWidth", "width"], + ["offsetHeight", "height"], +] as const) { + const nativeDescriptor = Object.getOwnPropertyDescriptor( + HTMLElement.prototype, + property, + ); + Object.defineProperty(HTMLElement.prototype, property, { + configurable: true, + get() { + const geometry = geometryFor(this); + return geometry?.[dimension] ?? nativeDescriptor?.get?.call(this) ?? 0; + }, + }); +} + +class VirtualViewportResizeObserver implements ResizeObserver { + readonly #callback: ResizeObserverCallback; + + constructor(callback: ResizeObserverCallback) { + this.#callback = callback; + } + + observe(target: Element, _options?: ResizeObserverOptions) { + const geometry = geometryFor(target); + if (!geometry) return; + const size = { + blockSize: geometry.height, + inlineSize: geometry.width, + }; + this.#callback( + [ + { + target, + borderBoxSize: [size], + contentBoxSize: [size], + contentRect: new DOMRect(0, 0, geometry.width, geometry.height), + devicePixelContentBoxSize: [size], + } as ResizeObserverEntry, + ], + this, + ); + } + + unobserve() {} + + disconnect() {} +} + +Object.defineProperty(window, "ResizeObserver", { + configurable: true, + value: VirtualViewportResizeObserver, + writable: true, +}); +globalThis.ResizeObserver = VirtualViewportResizeObserver; + +afterEach(cleanup); diff --git a/web/operator/tsconfig.app.json b/web/operator/tsconfig.app.json new file mode 100644 index 0000000..419946d --- /dev/null +++ b/web/operator/tsconfig.app.json @@ -0,0 +1,21 @@ +{ + "compilerOptions": { + "target": "ES2024", + "useDefineForClassFields": true, + "lib": ["ES2024", "DOM", "DOM.Iterable"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "jsx": "react-jsx", + "types": ["vitest/globals", "@testing-library/jest-dom"] + }, + "include": ["src"] +} diff --git a/web/operator/tsconfig.json b/web/operator/tsconfig.json new file mode 100644 index 0000000..1ffef60 --- /dev/null +++ b/web/operator/tsconfig.json @@ -0,0 +1,7 @@ +{ + "files": [], + "references": [ + { "path": "./tsconfig.app.json" }, + { "path": "./tsconfig.node.json" } + ] +} diff --git a/web/operator/tsconfig.node.json b/web/operator/tsconfig.node.json new file mode 100644 index 0000000..315eb15 --- /dev/null +++ b/web/operator/tsconfig.node.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "composite": true, + "noEmit": true, + "skipLibCheck": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true + }, + "include": ["vite.config.ts"] +} diff --git a/web/operator/tsconfig.node.tsbuildinfo b/web/operator/tsconfig.node.tsbuildinfo new file mode 100644 index 0000000..705443d --- /dev/null +++ b/web/operator/tsconfig.node.tsbuildinfo @@ -0,0 +1 @@ +{"fileNames":["./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.es5.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.webworker.importscripts.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.scripthost.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.d.ts","./node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.decorators.legacy.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/types/hmrPayload.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/dist/node/chunks/moduleRunnerTransport.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/types/customEvent.d.ts","./node_modules/.pnpm/@types+estree@1.0.9/node_modules/@types/estree/index.d.ts","./node_modules/.pnpm/rollup@4.62.3/node_modules/rollup/dist/rollup.d.ts","./node_modules/.pnpm/rollup@4.62.3/node_modules/rollup/dist/parseAst.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/types/hot.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/dist/node/module-runner.d.ts","./node_modules/.pnpm/esbuild@0.28.1/node_modules/esbuild/lib/main.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/types/internal/terserOptions.d.ts","./node_modules/.pnpm/source-map-js@1.2.1/node_modules/source-map-js/source-map.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/previous-map.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/input.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/css-syntax-error.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/declaration.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/root.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/warning.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/lazy-result.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/no-work-result.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/processor.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/result.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/document.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/rule.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/node.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/comment.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/container.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/at-rule.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/list.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/postcss.d.ts","./node_modules/.pnpm/postcss@8.5.25/node_modules/postcss/lib/postcss.d.mts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/types/internal/cssPreprocessorOptions.d.ts","./node_modules/.pnpm/lightningcss@1.32.0/node_modules/lightningcss/node/ast.d.ts","./node_modules/.pnpm/lightningcss@1.32.0/node_modules/lightningcss/node/targets.d.ts","./node_modules/.pnpm/lightningcss@1.32.0/node_modules/lightningcss/node/index.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/types/internal/lightningcssOptions.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/types/importGlob.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/types/metadata.d.ts","./node_modules/.pnpm/vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite/dist/node/index.d.ts","./node_modules/.pnpm/@tailwindcss+vite@4.3.3_vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0_/node_modules/@tailwindcss/vite/dist/index.d.mts","./node_modules/.pnpm/@babel+types@7.29.8/node_modules/@babel/types/lib/index.d.ts","./node_modules/.pnpm/@types+babel__generator@7.27.0/node_modules/@types/babel__generator/index.d.ts","./node_modules/.pnpm/@babel+parser@7.29.8/node_modules/@babel/parser/typings/babel-parser.d.ts","./node_modules/.pnpm/@types+babel__template@7.4.4/node_modules/@types/babel__template/index.d.ts","./node_modules/.pnpm/@types+babel__traverse@7.28.0/node_modules/@types/babel__traverse/index.d.ts","./node_modules/.pnpm/@types+babel__core@7.20.5/node_modules/@types/babel__core/index.d.ts","./node_modules/.pnpm/@vitejs+plugin-react@5.2.0_vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0_/node_modules/@vitejs/plugin-react/dist/index.d.ts","./node_modules/.pnpm/@vitest+spy@3.2.7/node_modules/@vitest/spy/dist/index.d.ts","./node_modules/.pnpm/@vitest+pretty-format@3.2.7/node_modules/@vitest/pretty-format/dist/index.d.ts","./node_modules/.pnpm/@vitest+utils@3.2.7/node_modules/@vitest/utils/dist/types.d.ts","./node_modules/.pnpm/@vitest+utils@3.2.7/node_modules/@vitest/utils/dist/helpers.d.ts","./node_modules/.pnpm/tinyrainbow@2.0.0/node_modules/tinyrainbow/dist/index-8b61d5bc.d.ts","./node_modules/.pnpm/tinyrainbow@2.0.0/node_modules/tinyrainbow/dist/node.d.ts","./node_modules/.pnpm/@vitest+utils@3.2.7/node_modules/@vitest/utils/dist/index.d.ts","./node_modules/.pnpm/@vitest+utils@3.2.7/node_modules/@vitest/utils/dist/types.d-BCElaP-c.d.ts","./node_modules/.pnpm/@vitest+utils@3.2.7/node_modules/@vitest/utils/dist/diff.d.ts","./node_modules/.pnpm/@vitest+expect@3.2.7/node_modules/@vitest/expect/dist/index.d.ts","./node_modules/.pnpm/@vitest+runner@3.2.7/node_modules/@vitest/runner/dist/tasks.d-CkscK4of.d.ts","./node_modules/.pnpm/@vitest+runner@3.2.7/node_modules/@vitest/runner/dist/types.d.ts","./node_modules/.pnpm/@vitest+utils@3.2.7/node_modules/@vitest/utils/dist/error.d.ts","./node_modules/.pnpm/@vitest+runner@3.2.7/node_modules/@vitest/runner/dist/index.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/optional-types.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/dist/chunks/environment.d.cL3nLXbE.d.ts","./node_modules/.pnpm/@vitest+mocker@3.2.7_vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0_/node_modules/@vitest/mocker/dist/registry.d-D765pazg.d.ts","./node_modules/.pnpm/@vitest+mocker@3.2.7_vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0_/node_modules/@vitest/mocker/dist/types.d-D_aRZRdy.d.ts","./node_modules/.pnpm/@vitest+mocker@3.2.7_vite@7.3.6_jiti@2.7.0_lightningcss@1.32.0_/node_modules/@vitest/mocker/dist/index.d.ts","./node_modules/.pnpm/@vitest+utils@3.2.7/node_modules/@vitest/utils/dist/source-map.d.ts","./node_modules/.pnpm/vite-node@3.2.4_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite-node/dist/trace-mapping.d-DLVdEqOp.d.ts","./node_modules/.pnpm/vite-node@3.2.4_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite-node/dist/index.d-DGmxD2U7.d.ts","./node_modules/.pnpm/vite-node@3.2.4_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite-node/dist/index.d.ts","./node_modules/.pnpm/@vitest+snapshot@3.2.7/node_modules/@vitest/snapshot/dist/environment.d-DHdQ1Csl.d.ts","./node_modules/.pnpm/@vitest+snapshot@3.2.7/node_modules/@vitest/snapshot/dist/rawSnapshot.d-lFsMJFUd.d.ts","./node_modules/.pnpm/@vitest+snapshot@3.2.7/node_modules/@vitest/snapshot/dist/index.d.ts","./node_modules/.pnpm/@vitest+snapshot@3.2.7/node_modules/@vitest/snapshot/dist/environment.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/dist/chunks/config.d.BKdhh7Zx.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/dist/chunks/worker.d.CUgIPz9V.d.ts","./node_modules/.pnpm/@types+deep-eql@4.0.2/node_modules/@types/deep-eql/index.d.ts","./node_modules/.pnpm/assertion-error@2.0.1/node_modules/assertion-error/index.d.ts","./node_modules/.pnpm/@types+chai@5.2.3/node_modules/@types/chai/index.d.ts","./node_modules/.pnpm/@vitest+runner@3.2.7/node_modules/@vitest/runner/dist/utils.d.ts","./node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/dist/chunks/benchmark.d.BwvBVTda.d.ts","./node_modules/.pnpm/vite-node@3.2.4_jiti@2.7.0_lightningcss@1.32.0/node_modules/vite-node/dist/client.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/dist/chunks/coverage.d.S9RMNXIe.d.ts","./node_modules/.pnpm/@vitest+snapshot@3.2.7/node_modules/@vitest/snapshot/dist/manager.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/dist/chunks/reporters.d.BuRON0I0.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/dist/chunks/vite.d.BnOPPc46.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/dist/config.d.ts","./node_modules/.pnpm/vitest@3.2.7_@types+debug@4.1.13_jiti@2.7.0_jsdom@27.4.0_lightningcss@1.32.0/node_modules/vitest/config.d.ts","./vite.config.ts","./node_modules/.pnpm/@types+react@19.2.18/node_modules/@types/react/global.d.ts","./node_modules/.pnpm/csstype@3.2.3/node_modules/csstype/index.d.ts","./node_modules/.pnpm/@types+react@19.2.18/node_modules/@types/react/index.d.ts","./node_modules/.pnpm/@types+react-dom@19.2.4_@types+react@19.2.18/node_modules/@types/react-dom/index.d.ts"],"fileIdsList":[[47],[45,93],[47,48,49,50,51],[47,49],[83,84],[99],[97,98],[45,52,93],[54,59,60,62],[70,71],[60,62,64,65,66],[60],[60,62,64],[60,64],[77],[55,77,78],[55,77],[55,61],[56],[55,56,57,59],[55],[39,40],[33],[31,33],[22,30,31,32,34,36],[20],[23,28,33,36],[19,36],[23,24,27,28,29,36],[23,24,25,27,28,36],[20,21,22,23,24,28,29,30,32,33,34,36],[36],[18,20,21,22,23,24,25,27,28,29,30,31,32,33,34,35],[18,36],[23,25,26,28,29,36],[27,36],[28,29,33,36],[21,31],[12,44,45],[11,12],[58],[74,75],[74],[8],[8,9,10,12,13,15,16,17,37,38,42,43,44,45],[8,9,10,14],[10],[41],[12,45],[63,94],[67,86,87],[55,62,67,79,80],[89],[68],[45,55,60,62,67,69,72,73,76,79,81,82,85,88,90,91,93],[45,92,93],[67,69,76,79,81],[45,55,60,62,67,68,69,72,73,76,79,80,81,82,85,86,87,88,89,90,91,92,93],[46,53,95]],"fileInfos":[{"version":"a7297ff837fcdf174a9524925966429eb8e5feecc2cc55cc06574e6b092c1eaa","impliedFormat":1},{"version":"c430d44666289dae81f30fa7b2edebf186ecc91a2d4c71266ea6ae76388792e1","affectsGlobalScope":true,"impliedFormat":1},{"version":"080941d9f9ff9307f7e27a83bcd888b7c8270716c39af943532438932ec1d0b9","affectsGlobalScope":true,"impliedFormat":1},{"version":"80e18897e5884b6723488d4f5652167e7bb5024f946743134ecc4aa4ee731f89","affectsGlobalScope":true,"impliedFormat":1},{"version":"cd034f499c6cdca722b60c04b5b1b78e058487a7085a8e0d6fb50809947ee573","affectsGlobalScope":true,"impliedFormat":1},{"version":"8e7f8264d0fb4c5339605a15daadb037bf238c10b654bb3eee14208f860a32ea","affectsGlobalScope":true,"impliedFormat":1},{"version":"782dec38049b92d4e85c1585fbea5474a219c6984a35b004963b00beb1aab538","affectsGlobalScope":true,"impliedFormat":1},{"version":"a7ca8df4f2931bef2aa4118078584d84a0b16539598eaadf7dce9104dfaa381c","impliedFormat":1},{"version":"10073cdcf56982064c5337787cc59b79586131e1b28c106ede5bff362f912b70","impliedFormat":99},{"version":"72950913f4900b680f44d8cab6dd1ea0311698fc1eefb014eb9cdfc37ac4a734","impliedFormat":1},{"version":"751764bb94219b4ce8f5475dc35d3de2e432fea01a0c9610cd7f69ad05e398c6","impliedFormat":1},{"version":"21944c138a48dc23382cb6558b1d4498908faad2104ba7ff390ba8b27c06f3c0","affectsGlobalScope":true,"impliedFormat":1},{"version":"a660aa95476042d3fdcc1343cf6bb8fdf24772d31712b1db321c5a4dcc325434","impliedFormat":1},{"version":"36977c14a7f7bfc8c0426ae4343875689949fb699f3f84ecbe5b300ebf9a2c55","impliedFormat":1},{"version":"ff0a83c9a0489a627e264ffcb63f2264b935b20a502afa3a018848139e3d8575","impliedFormat":99},{"version":"161c8e0690c46021506e32fda85956d785b70f309ae97011fd27374c065cac9b","affectsGlobalScope":true,"impliedFormat":1},{"version":"f582b0fcbf1eea9b318ab92fb89ea9ab2ebb84f9b60af89328a91155e1afce72","impliedFormat":1},{"version":"402e5c534fb2b85fa771170595db3ac0dd532112c8fa44fc23f233bc6967488b","impliedFormat":1},{"version":"52dcc257df5119fb66d864625112ce5033ac51a4c2afe376a0b299d2f7f76e4a","impliedFormat":1},{"version":"e5bab5f871ef708d52d47b3e5d0aa72a08ee7a152f33931d9a60809711a2a9a3","impliedFormat":1},{"version":"e16dc2a81595736024a206c7d5c8a39bfe2e6039208ef29981d0d95434ba8fcf","impliedFormat":1},{"version":"cc4a4903fb698ca1d961d4c10dce658aa3a479faf40509d526f122b044eaf6a4","impliedFormat":1},{"version":"19ee8416e6473ed6c7adb868fa796b5653cf0fa2a337658e677eaa0d134388c3","impliedFormat":1},{"version":"1328ab4e442614b28cdb3d4b414cf68325c0da0dca07287a338d0654b7a00261","impliedFormat":1},{"version":"a039dc21f045919f3cbee2ec13812cc6cc3eebc99dae4be00973230f468d19a6","impliedFormat":1},{"version":"3fbe57af01460e49dcd29df55d6931e1672bc6f1be0fb073d11410bc16f9037d","impliedFormat":1},{"version":"f760be449e8562ec5c09bb5187e8e1eabf3c113c0c58cddda53ef8c69f3e2131","impliedFormat":1},{"version":"44325ed13294fce6ab825b82947bbeed2611db7dad9d9135260192f375e5a189","impliedFormat":1},{"version":"e392e8fb5b514eafc585601c1d781485aa6dd6a320e75daf1064a4c6918a1b45","impliedFormat":1},{"version":"46e4a36e8ddbdfb4e7330e11c81c970dc8b218611df9183d39c41c5f8c653b55","impliedFormat":1},{"version":"3cc8a3d123b6b232d48d34b51b785f9da8d193f5b5817fa521fcd2f3b9315c55","impliedFormat":1},{"version":"6332f565867cf4a740a70e30f31cefba37ef7cebcf74f22eab8d744fde6d193e","impliedFormat":1},{"version":"2977b7884aedc895a1d0c9c210c7cf3272c29d6959a08a6fa3ff71e0aff08175","impliedFormat":1},{"version":"17f2922d41ddd032830a91371c948cd9ce903b35c95adca72271a54584f19b0b","impliedFormat":1},{"version":"3eed76ede2a1a14d7c9bb0a642041282dcc264811139d3dd275c9fe14efc9840","impliedFormat":1},{"version":"354a7f8e1287d9d6b7561bc97fdd8cbc2f7c1dd79e4cb37b942e8a5cfaff1085","impliedFormat":1},{"version":"8d369483f0c2b9ee388129cfdb6a43bc8112b377e86a41884bd06e19ce04f4c1","impliedFormat":99},{"version":"960bd764c62ac43edc24eaa2af958a4b4f1fa5d27df5237e176d0143b36a39c6","affectsGlobalScope":true,"impliedFormat":1},{"version":"3fd8a5aefd8c3feb3936ca66f5aa89dff7bf6e6537b4158dbd0f6e0d65ed3b9e","impliedFormat":1},{"version":"a18642ddf216f162052a16cba0944892c4c4c977d3306a87cb673d46abbb0cbf","impliedFormat":1},{"version":"41c41c6e90133bb2a14f7561f29944771886e5535945b2b372e2f6ed6987746e","impliedFormat":1},{"version":"4ec16d7a4e366c06a4573d299e15fe6207fc080f41beac5da06f4af33ea9761e","impliedFormat":1},{"version":"59f8dc89b9e724a6a667f52cdf4b90b6816ae6c9842ce176d38fcc973669009e","affectsGlobalScope":true,"impliedFormat":1},{"version":"e4af494f7a14b226bbe732e9c130d8811f8c7025911d7c58dd97121a85519715","impliedFormat":1},{"version":"cbb1c5ba5dbabe42c19ca31b83e48fec95895484fe1d1a8fb649b69ea224c5b8","impliedFormat":99},{"version":"7757c6ca7a8ad1992401c6aff33633d6a088515be5a39d7ee188b35bfc8e5f8e","impliedFormat":99},{"version":"69d4b61c408556b97b796782a1110f7e01a03ed80f31741f2c59b722185830ed","impliedFormat":1},{"version":"b6d03c9cfe2cf0ba4c673c209fcd7c46c815b2619fd2aad59fc4229aaef2ed43","impliedFormat":1},{"version":"e6ca59368dce5a594dcde9bbb6ae640d668fa6c28c31639dd2a75b731bb036a2","impliedFormat":1},{"version":"670a76db379b27c8ff42f1ba927828a22862e2ab0b0908e38b671f0e912cc5ed","impliedFormat":1},{"version":"13b77ab19ef7aadd86a1e54f2f08ea23a6d74e102909e3c00d31f231ed040f62","impliedFormat":1},{"version":"069bebfee29864e3955378107e243508b163e77ab10de6a5ee03ae06939f0bb9","impliedFormat":1},{"version":"ef94438f848be3a3b0033013bf64753f771f983c1e205e4a06675eb253ca7cd2","impliedFormat":99},{"version":"04471dc55f802c29791cc75edda8c4dd2a121f71c2401059da61eff83099e8ab","impliedFormat":99},{"version":"5c54a34e3d91727f7ae840bfe4d5d1c9a2f93c54cb7b6063d06ee4a6c3322656","impliedFormat":99},{"version":"db4da53b03596668cf6cc9484834e5de3833b9e7e64620cf08399fe069cd398d","impliedFormat":99},{"version":"ac7c28f153820c10850457994db1462d8c8e462f253b828ad942a979f726f2f9","impliedFormat":99},{"version":"f9b028d3c3891dd817e24d53102132b8f696269309605e6ed4f0db2c113bbd82","impliedFormat":99},{"version":"fb7c8d90e52e2884509166f96f3d591020c7b7977ab473b746954b0c8d100960","impliedFormat":99},{"version":"0bff51d6ed0c9093f6955b9d8258ce152ddb273359d50a897d8baabcb34de2c4","impliedFormat":99},{"version":"ef13c73d6157a32933c612d476c1524dd674cf5b9a88571d7d6a0d147544d529","impliedFormat":99},{"version":"13918e2b81c4288695f9b1f3dcc2468caf0f848d5c1f3dc00071c619d34ff63a","impliedFormat":99},{"version":"120a80aa556732f684db3ed61aeff1d6671e1655bd6cba0aa88b22b88ac9a6b1","affectsGlobalScope":true,"impliedFormat":99},{"version":"45cec9a1ba6549060552eead8959d47226048e0b71c7d0702ae58b7e16a28912","impliedFormat":99},{"version":"6907b09850f86610e7a528348c15484c1e1c09a18a9c1e98861399dfe4b18b46","impliedFormat":99},{"version":"12deea8eaa7a4fc1a2908e67da99831e5c5a6b46ad4f4f948fd4759314ea2b80","impliedFormat":99},{"version":"f0a8b376568a18f9a4976ecb0855187672b16b96c4df1c183a7e52dc1b5d98e8","impliedFormat":99},{"version":"8124828a11be7db984fcdab052fd4ff756b18edcfa8d71118b55388176210923","impliedFormat":99},{"version":"092944a8c05f9b96579161e88c6f211d5304a76bd2c47f8d4c30053269146bc8","impliedFormat":99},{"version":"b34b5f6b506abb206b1ea73c6a332b9ee9c8c98be0f6d17cdbda9430ecc1efab","impliedFormat":99},{"version":"75d4c746c3d16af0df61e7b0afe9606475a23335d9f34fcc525d388c21e9058b","impliedFormat":99},{"version":"fa959bf357232201c32566f45d97e70538c75a093c940af594865d12f31d4912","impliedFormat":99},{"version":"d2c52abd76259fc39a30dfae70a2e5ce77fd23144457a7ff1b64b03de6e3aec7","impliedFormat":99},{"version":"e6233e1c976265e85aa8ad76c3881febe6264cb06ae3136f0257e1eab4a6cc5a","impliedFormat":99},{"version":"f73e2335e568014e279927321770da6fe26facd4ac96cdc22a56687f1ecbb58e","impliedFormat":99},{"version":"317878f156f976d487e21fd1d58ad0461ee0a09185d5b0a43eedf2a56eb7e4ea","impliedFormat":99},{"version":"324ac98294dab54fbd580c7d0e707d94506d7b2c3d5efe981a8495f02cf9ad96","impliedFormat":99},{"version":"9ec72eb493ff209b470467e24264116b6a8616484bca438091433a545dfba17e","impliedFormat":99},{"version":"d6ee22aba183d5fc0c7b8617f77ee82ecadc2c14359cc51271c135e23f6ed51f","impliedFormat":99},{"version":"49747416f08b3ba50500a215e7a55d75268b84e31e896a40313c8053e8dec908","impliedFormat":99},{"version":"5e91172586d1be7d1508d1a40c8bf76161f6f4179d1c25158a20599f9fb26a66","impliedFormat":99},{"version":"09d215b379a93f8cbb6caf9e9f5d7b4d48042295ee697e7e4771288c7917a21e","impliedFormat":99},{"version":"427fe2004642504828c1476d0af4270e6ad4db6de78c0b5da3e4c5ca95052a99","impliedFormat":1},{"version":"2eeffcee5c1661ddca53353929558037b8cf305ffb86a803512982f99bcab50d","impliedFormat":99},{"version":"9afb4cb864d297e4092a79ee2871b5d3143ea14153f62ef0bb04ede25f432030","affectsGlobalScope":true,"impliedFormat":99},{"version":"891694d3694abd66f0b8872997b85fd8e52bc51632ce0f8128c96962b443189f","impliedFormat":99},{"version":"69bf2422313487956e4dacf049f30cb91b34968912058d244cb19e4baa24da97","impliedFormat":99},{"version":"971a2c327ff166c770c5fb35699575ba2d13bba1f6d2757309c9be4b30036c8e","impliedFormat":99},{"version":"4f45e8effab83434a78d17123b01124259fbd1e335732135c213955d85222234","impliedFormat":99},{"version":"7bd51996fb7717941cbe094b05adc0d80b9503b350a77b789bbb0fc786f28053","impliedFormat":99},{"version":"b62006bbc815fe8190c7aee262aad6bff993e3f9ade70d7057dfceab6de79d2f","impliedFormat":99},{"version":"ab80d2cb170a92c61ca8c822d0db0fc50eb15c7c6cf1a24cb01852a5a15a7db8","impliedFormat":99},{"version":"210955af8573671abebb6e1391d134d82fbcff130aa68922ea1e839f8f48a0ad","impliedFormat":99},{"version":"78a8f2e95e2904914c509e4bbc68e626f8b8ff8f30ca96cffc7a795fa17394f5","impliedFormat":99},{"version":"7bbff6783e96c691a41a7cf12dd5486b8166a01b0c57d071dbcfca55c9525ec4","impliedFormat":99},{"version":"470312199bb48d5c35ec0db90330daea6be14d7a77867f018d776bacb500f76d","signature":"4b96dd19fd2949d28ce80e913412b0026dc421e5bf6c31d87c7b5eb11b5753b4"},{"version":"7e29f41b158de217f94cb9676bf9cbd0cd9b5a46e1985141ed36e075c52bf6ad","affectsGlobalScope":true,"impliedFormat":1},{"version":"ac51dd7d31333793807a6abaa5ae168512b6131bd41d9c5b98477fc3b7800f9f","impliedFormat":1},{"version":"814d5c7384f3ca276e9dc4bcfde5545801a3ea0bfae09916b3336774e662fd1b","impliedFormat":1},{"version":"be1cc4d94ea60cbe567bc29ed479d42587bf1e6cba490f123d329976b0fe4ee5","impliedFormat":1}],"root":[96],"options":{"composite":true,"module":99,"skipLibCheck":true,"strict":true},"referencedMap":[[49,1],[46,2],[52,3],[48,1],[50,4],[51,1],[85,5],[100,6],[99,7],[53,8],[63,9],[72,10],[67,11],[64,12],[65,13],[86,14],[80,15],[79,16],[91,16],[78,17],[62,18],[66,18],[57,19],[60,20],[73,19],[61,21],[41,22],[34,23],[32,24],[33,25],[21,26],[22,24],[29,27],[20,28],[25,29],[26,30],[31,31],[37,32],[36,33],[19,34],[27,35],[28,36],[23,37],[30,23],[24,38],[13,39],[12,40],[59,41],[89,42],[75,43],[76,42],[9,44],[45,45],[15,46],[10,44],[14,47],[42,48],[44,49],[95,50],[88,51],[81,52],[90,53],[69,54],[92,55],[93,56],[82,57],[94,58],[96,59]],"affectedFilesPendingEmit":[[96,17]],"emitSignatures":[96],"version":"5.9.3"} \ No newline at end of file diff --git a/web/operator/vite.config.ts b/web/operator/vite.config.ts new file mode 100644 index 0000000..8c50c38 --- /dev/null +++ b/web/operator/vite.config.ts @@ -0,0 +1,41 @@ +import tailwindcss from "@tailwindcss/vite"; +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vitest/config"; + +export default defineConfig({ + plugins: [react(), tailwindcss()], + base: "/", + build: { + outDir: "../../src/runtime/operator/web_assets", + emptyOutDir: true, + sourcemap: false, + rollupOptions: { + output: { + manualChunks: { + graph: ["@xyflow/react"], + editor: ["@codemirror/lang-json", "@codemirror/state", "@codemirror/view"], + protobuf: [ + "@protobuf-ts/grpcweb-transport", + "@protobuf-ts/runtime", + "@protobuf-ts/runtime-rpc", + ], + }, + }, + }, + }, + server: { + fs: { + allow: ["../.."], + }, + port: 5173, + proxy: { + "/avalanche.operator.OperatorService": { + target: "http://127.0.0.1:7435", + }, + }, + }, + test: { + environment: "jsdom", + setupFiles: "./src/test/setup.ts", + }, +});