diff --git a/tools/check.sh b/tools/check.sh --- a/tools/check.sh +++ b/tools/check.sh @@ -377,6 +377,18 @@ return "$rc" } +step "landing observer fixtures" +if ! python3 tools/test_landing_observer.py; then + fail=1 +fi +if command -v node >/dev/null 2>&1; then + if ! node --test .agents/skills/observing-misaligned-landings/tests/interpret-anomalies.test.mjs; then + fail=1 + fi +else + echo "SKIP: node unavailable; optional interpreter fixtures not run." +fi + if [ "$rust_gate" -eq 1 ]; then if ! run_rust_gate; then fail=1 diff --git a/tools/test_landing_observer.py b/tools/test_landing_observer.py new file mode 100644 --- /dev/null +++ b/tools/test_landing_observer.py @@ -0,0 +1,841 @@ +#!/usr/bin/env python3 +"""Focused fixtures for the strictly read-only landing observer.""" + +from __future__ import annotations + +import copy +import hashlib +import importlib.util +import json +import os +from pathlib import Path +import subprocess +import sys +import tempfile +import unittest + + +ROOT = Path(__file__).resolve().parent.parent +OBSERVER = ROOT / ".agents/skills/observing-misaligned-landings/scripts/observe-landing.py" +TITLE = "Misaligned — WORK / THINK / LIE" +ZERO_SHA = "0" * 40 +AGENT_ID = "agent-observer-fixture" +TASK = "observer-fixture" + +spec = importlib.util.spec_from_file_location("landing_observer", OBSERVER) +assert spec is not None and spec.loader is not None +landing_observer = importlib.util.module_from_spec(spec) +sys.modules[spec.name] = landing_observer +spec.loader.exec_module(landing_observer) + + +def run( + command: list[str], + cwd: Path, + env: dict[str, str] | None = None, +) -> subprocess.CompletedProcess[str]: + completed = subprocess.run( + command, + cwd=cwd, + env=env, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=False, + ) + if completed.returncode != 0: + raise AssertionError( + f"command failed ({completed.returncode}): {' '.join(command)}\n" + f"stdout:\n{completed.stdout}\nstderr:\n{completed.stderr}" + ) + return completed + + +def git(cwd: Path, *args: str) -> str: + return run(["git", *args], cwd).stdout.strip() + + +def filesystem_fingerprint(root: Path) -> dict[str, str]: + """Fingerprint every fixture byte, link target, and mode without following links.""" + if not root.exists(): + return {".": "missing"} + fingerprint: dict[str, str] = {} + for candidate in sorted(root.rglob("*")): + relative = str(candidate.relative_to(root)) + metadata = candidate.lstat() + mode = oct(metadata.st_mode) + if candidate.is_symlink(): + fingerprint[relative] = f"symlink:{mode}:{os.readlink(candidate)}" + elif candidate.is_file(): + digest = hashlib.sha256(candidate.read_bytes()).hexdigest() + fingerprint[relative] = f"file:{mode}:{digest}" + elif candidate.is_dir(): + fingerprint[relative] = f"directory:{mode}" + else: + fingerprint[relative] = f"other:{mode}" + return fingerprint + + +def codes(rows: list[dict[str, str]]) -> set[str]: + return {row["code"] for row in rows} + + +def gate_payload(revision: str, status: str = "pass") -> dict[str, str]: + return { + "revision": revision, + "schema": landing_observer.GATE_SCHEMA, + "status": status, + } + + + +def deployment_payload( + revision: str, + pages_revision: str | None = None, + status: str = "pass", +) -> dict[str, object]: + return { + "pages_revision": pages_revision, + "schema": landing_observer.DEPLOYMENT_SCHEMA, + "source_revision": revision, + "status": status, + } + +def channel_payload( + revision: str, + status: str = "delivered", + message_id: str | None = "491", +) -> dict[str, object]: + payload: dict[str, object] = { + "channel": "telegram", + "revision": revision, + "schema": landing_observer.CHANNEL_SCHEMA, + "status": status, + } + if message_id is not None: + payload["message_id"] = message_id + return payload + + +def base_evidence(revision: str = "1" * 40, main: str = "2" * 40) -> dict[str, object]: + return { + "input": {"agent_id": AGENT_ID, "task": TASK}, + "pages": { + "available": True, + "read_error": None, + "snapshot_matches_ref": True, + "snapshot_revision": "3" * 40, + "source_is_expected": False, + "source_revision": main, + "title_contract": True, + }, + "primary_worktree": { + "dirty": False, + "present": True, + }, + "project_status": { + "consistent": True, + "generated_ledgers_fresh": True, + "generated_work_orders_fresh": True, + "readable": True, + "target_run": { + "agent_id": AGENT_ID, + "phase": "check-land", + "present": True, + "status": "running", + "worktree": "/tmp/observer-fixture", + }, + "target_run_ambiguous": False, + "target_worktree_ambiguous": False, + }, + "public_site": { + "attempted": True, + "contract_ok": False, + "source_is_expected": False, + "source_revision": main, + }, + "receipts": { + "channel": { + "provided": False, + "read_error": None, + "valid": None, + }, + "deployment": { + "provided": False, + "read_error": None, + "valid": None, + }, + "gate": { + "provided": True, + "read_error": None, + "revision": revision, + "status": "pass", + "valid": True, + }, + }, + "repository": { + "candidate_head_stable": True, + "hinted_root_matches": True, + "local_main_revision": main, + "readable": True, + "remote_main_contains_expected": False, + "remote_main_is_expected": False, + "remote_main_revision": main, + "remote_pages_revision": "3" * 40, + "remote_refs_readable": True, + "remote_refs_stable": True, + "snapshot_main_matches_ref": True, + "snapshot_main_revision": main, + }, + "target_worktree": { + "ahead": 1, + "behind": 0, + "dirty": False, + "head_revision": revision, + "path": "/tmp/observer-fixture", + "present": True, + }, + } + + +def landed_evidence(revision: str = "1" * 40) -> dict[str, object]: + evidence = base_evidence(revision, revision) + evidence["repository"].update( + remote_main_contains_expected=True, + remote_main_is_expected=True, + ) + evidence["pages"].update( + source_is_expected=True, + source_revision=revision, + ) + evidence["public_site"].update( + contract_ok=True, + source_is_expected=True, + source_revision=revision, + ) + evidence["project_status"]["target_run"].update( + phase="site-publish", + status="ok", + ) + evidence["target_worktree"].update( + ahead=None, + behind=None, + dirty=None, + head_revision=None, + present=False, + ) + evidence["receipts"]["channel"] = { + "channel": "telegram", + "message_id": "491", + "provided": True, + "read_error": None, + "revision": revision, + "status": "delivered", + "valid": True, + } + return evidence + + +class ReceiptParsingTests(unittest.TestCase): + def test_non_delivered_channel_receipt_still_requires_exact_revision(self) -> None: + with tempfile.TemporaryDirectory() as raw_tmp: + path = Path(raw_tmp) / "channel.json" + payload = { + "channel": "telegram", + "schema": landing_observer.CHANNEL_SCHEMA, + "status": "unavailable", + } + path.write_text(json.dumps(payload), encoding="utf-8") + receipt = landing_observer.read_receipt(path, "channel") + self.assertEqual(receipt["valid"], False) + self.assertIn("invalid fields", receipt["read_error"]) + + +class ClassificationMatrixTests(unittest.TestCase): + def classify(self, evidence: dict[str, object], revision: str = "1" * 40): + return landing_observer.classify(evidence, revision) + + def test_ready_requires_exact_gate_clean_rebase_and_owned_running_task(self) -> None: + state, missing, ownership, anomalies, _ = self.classify(base_evidence()) + self.assertEqual(state, "ready") + self.assertEqual(codes(missing), {"land_candidate"}) + self.assertEqual(ownership, []) + self.assertEqual(anomalies, []) + + def test_ready_prerequisite_failures_are_coherent_blocks(self) -> None: + cases = { + "task_worktree_dirty": ("target_worktree", "dirty", True), + "local_remote_ref_stale": ("repository", "local_main_revision", "4" * 40), + "candidate_requires_rebase": ("target_worktree", "behind", 1), + "no_candidate_delta": ("target_worktree", "ahead", 0), + "generated_ledgers_stale": ("project_status", "generated_ledgers_fresh", False), + "generated_work_orders_stale": ( + "project_status", + "generated_work_orders_fresh", + False, + ), + } + for expected_code, (section, key, value) in cases.items(): + with self.subTest(expected_code): + evidence = base_evidence() + evidence[section][key] = value + state, missing, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "blocked") + self.assertIn(expected_code, codes(missing)) + self.assertEqual(anomalies, []) + + def test_foreign_or_unknown_ownership_blocks_ready_without_claiming_it(self) -> None: + for owner in ("another-agent", None): + with self.subTest(owner=owner): + evidence = base_evidence() + evidence["project_status"]["target_run"]["agent_id"] = owner + state, missing, ownership, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "blocked") + self.assertIn("task_ownership_unproven", codes(missing)) + self.assertTrue(ownership) + self.assertEqual(anomalies, []) + + def test_missing_gate_reports_only_presence_blocker(self) -> None: + evidence = base_evidence() + evidence["receipts"]["gate"] = { + "provided": False, + "read_error": None, + "valid": None, + } + state, missing, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "blocked") + self.assertEqual(codes(missing), {"gate_receipt_missing"}) + self.assertEqual(anomalies, []) + + def test_absent_target_reports_only_missing_target_blocker(self) -> None: + evidence = base_evidence() + evidence["target_worktree"].update( + present=False, + dirty=None, + head_revision=None, + ahead=None, + behind=None, + ) + evidence["project_status"]["target_run"]["status"] = "running" + state, missing, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "blocked") + self.assertEqual( + codes(missing), + {"target_worktree_missing"}, + ) + self.assertEqual(anomalies, []) + + def test_dirty_primary_is_ownership_warning_while_ready(self) -> None: + evidence = base_evidence() + evidence["primary_worktree"]["dirty"] = True + state, missing, ownership, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "ready") + self.assertEqual(codes(missing), {"land_candidate"}) + self.assertEqual(codes(ownership), {"unrelated_primary_checkout_dirty"}) + self.assertEqual(anomalies, []) + + def test_landed_requires_remote_pages_gate_terminal_run_and_cleanup(self) -> None: + state, missing, ownership, anomalies, summary = self.classify(landed_evidence()) + self.assertEqual(state, "landed") + self.assertEqual(missing, []) + self.assertEqual(ownership, []) + self.assertEqual(anomalies, []) + self.assertIn("Landed", summary) + + def test_exact_remote_without_gate_is_blocked_not_landed(self) -> None: + evidence = landed_evidence() + evidence["receipts"]["gate"] = { + "provided": False, + "read_error": None, + "valid": None, + } + state, missing, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "blocked") + self.assertIn("gate_receipt_missing", codes(missing)) + self.assertEqual(anomalies, []) + + def test_cleanup_pending_is_distinct_from_failed_landing(self) -> None: + evidence = landed_evidence() + evidence["project_status"]["target_run"]["status"] = "running" + evidence["target_worktree"].update( + present=True, + dirty=False, + head_revision="1" * 40, + ) + state, missing, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "blocked") + self.assertEqual( + codes(missing), + {"cleanup_pending", "run_completion_pending"}, + ) + self.assertEqual(anomalies, []) + + def test_remote_pages_is_authoritative_while_public_edge_converges(self) -> None: + evidence = landed_evidence() + evidence["public_site"].update( + contract_ok=False, + source_is_expected=False, + source_revision="0" * 40, + ) + state, missing, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "landed") + self.assertEqual(missing, []) + self.assertEqual(codes(anomalies), {"public_edge_converging"}) + + def test_unavailable_telegram_preserves_landing_and_delivery_gap(self) -> None: + evidence = landed_evidence() + evidence["receipts"]["channel"] = { + "channel": "telegram", + "message_id": None, + "provided": True, + "read_error": None, + "revision": "1" * 40, + "status": "unavailable", + "valid": True, + } + state, missing, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "landed") + self.assertEqual(codes(missing), {"telegram_delivery_pending"}) + self.assertEqual(codes(anomalies), {"telegram_runtime_unavailable"}) + + def test_unrelated_dirty_primary_does_not_undo_completed_owned_cleanup(self) -> None: + evidence = landed_evidence() + evidence["primary_worktree"]["dirty"] = True + state, missing, ownership, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "landed") + self.assertEqual(missing, []) + self.assertEqual(codes(ownership), {"unrelated_primary_checkout_dirty"}) + self.assertEqual(anomalies, []) + + def test_superseded_historical_landing_remains_landed(self) -> None: + evidence = landed_evidence() + newer = "9" * 40 + evidence["repository"].update( + remote_main_revision=newer, + remote_main_is_expected=False, + remote_main_contains_expected=True, + ) + evidence["pages"].update( + source_revision="8" * 40, + source_is_expected=False, + ) + evidence["public_site"].update( + source_revision=newer, + source_is_expected=False, + ) + state, missing, _, anomalies, summary = self.classify(evidence) + self.assertEqual(state, "landed") + self.assertEqual(missing, []) + self.assertEqual(codes(anomalies), {"current_main_unpublished"}) + self.assertIn("supersedes", summary) + + def test_stale_post_rebase_gate_receipt_is_inconsistent(self) -> None: + evidence = base_evidence() + evidence["receipts"]["gate"]["revision"] = "8" * 40 + state, missing, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "inconsistent") + self.assertEqual(missing, []) + self.assertEqual(codes(anomalies), {"gate_revision_mismatch"}) + + def test_optional_receipts_must_match_exact_remote_addresses(self) -> None: + deployment = landed_evidence() + deployment["receipts"]["deployment"] = { + "pages_revision": "8" * 40, + "provided": True, + "read_error": None, + "source_revision": "1" * 40, + "status": "pass", + "valid": True, + } + state, _, _, anomalies, _ = self.classify(deployment) + self.assertEqual(state, "inconsistent") + self.assertIn("deployment_pages_revision_mismatch", codes(anomalies)) + + channel = landed_evidence() + channel["receipts"]["channel"].update( + message_id=None, + revision="8" * 40, + status="unavailable", + ) + state, _, _, anomalies, _ = self.classify(channel) + self.assertEqual(state, "inconsistent") + self.assertIn("channel_revision_mismatch", codes(anomalies)) + + def test_terminal_run_and_remote_contradictions_take_precedence(self) -> None: + evidence = base_evidence() + evidence["project_status"]["target_run"]["status"] = "ok" + evidence["target_worktree"]["present"] = False + state, _, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "inconsistent") + self.assertIn("terminal_run_without_remote_landing", codes(anomalies)) + + def test_invalid_receipt_project_state_and_impossible_pages_fail_closed(self) -> None: + cases = { + "gate_receipt_invalid": lambda row: row["receipts"].update( + gate={"provided": True, "read_error": "bad", "valid": False} + ), + "project_status_inconsistent": lambda row: row["project_status"].update( + consistent=False + ), + "published_revision_not_on_main": lambda row: row["pages"].update( + source_is_expected=True, + source_revision="1" * 40, + ), + "remote_refs_moved_during_observation": lambda row: row["repository"].update( + remote_refs_stable=False + ), + "pages_authority_unreadable": lambda row: row["pages"].update( + available=None, + read_error="fetch failed", + ), + } + for expected_code, mutate in cases.items(): + with self.subTest(expected_code): + evidence = base_evidence() + mutate(evidence) + state, _, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "inconsistent") + self.assertIn(expected_code, codes(anomalies)) + + def test_unknown_authorities_remain_unknown_and_fail_closed(self) -> None: + evidence = base_evidence() + evidence["repository"].update( + remote_refs_readable=None, + remote_refs_stable=None, + ) + evidence["project_status"].update(readable=False, consistent=None) + state, _, _, anomalies, _ = self.classify(evidence) + self.assertEqual(state, "inconsistent") + self.assertEqual( + codes(anomalies), + {"project_status_unreadable", "remote_refs_unreadable"}, + ) + + +class LandingFixture: + def __init__(self, base: Path) -> None: + self.base = base + self.remote = base / "remote.git" + self.root = base / "work" + self.pages = base / "pages" + self.target = base / TASK + self.status_json = base / "project-status.json" + self.gate_receipt = base / "gate.json" + self.channel_receipt = base / "channel.json" + self.deployment_receipt = base / "deployment.json" + + run(["git", "init", "--bare", "-q", str(self.remote)], base) + run(["git", "init", "-q", "-b", "main", str(self.root)], base) + git(self.root, "config", "user.name", "Observer Fixture") + git(self.root, "config", "user.email", "observer@example.invalid") + git(self.root, "remote", "add", "origin", str(self.remote)) + + tools = self.root / "tools" + tools.mkdir() + (tools / "project-status.py").write_text( + """import json, os +with open(os.environ["OBSERVER_STATUS_JSON"], encoding="utf-8") as handle: + print(json.dumps(json.load(handle), sort_keys=True)) +""", + encoding="utf-8", + ) + (tools / "site-smoke.sh").write_text( + f"""#!/usr/bin/env bash +set -euo pipefail +source_revision="${{OBSERVER_PUBLIC_SOURCE:-${{SITE_SOURCE_REVISION}}}}" +echo "site-smoke: attempt 1/1 source=${{source_revision}}, expected=${{SITE_SOURCE_REVISION}}" >&2 +if [ "${{OBSERVER_SMOKE_FAIL:-0}}" = 1 ]; then + exit 1 +fi +echo "site-smoke: OK ${{SITE_SMOKE_URL}}" +echo "site-smoke: source=${{source_revision}}" +""", + encoding="utf-8", + ) + (self.root / "README.md").write_text("fixture base\n", encoding="utf-8") + git(self.root, "add", "README.md", "tools/project-status.py", "tools/site-smoke.sh") + git(self.root, "commit", "-q", "-m", "fixture base") + self.base_revision = git(self.root, "rev-parse", "HEAD") + git(self.root, "push", "-q", "-u", "origin", "main") + git(self.root, "update-ref", "refs/remotes/origin/main", self.base_revision) + + run(["git", "init", "-q", "-b", "pages", str(self.pages)], base) + git(self.pages, "config", "user.name", "Observer Fixture") + git(self.pages, "config", "user.email", "observer@example.invalid") + git(self.pages, "remote", "add", "origin", str(self.remote)) + self.write_page(self.base_revision, "fixture base pages") + + git(self.root, "worktree", "add", "-q", "-b", f"worktree-{TASK}", str(self.target)) + (self.target / "README.md").write_text("fixture candidate\n", encoding="utf-8") + git(self.target, "add", "README.md") + git(self.target, "commit", "-q", "-m", "fixture candidate") + self.revision = git(self.target, "rev-parse", "HEAD") + self.write_receipt(self.gate_receipt, gate_payload(self.revision)) + self.write_project_status("running", include_target=True) + + @staticmethod + def write_receipt(path: Path, payload: dict[str, object]) -> None: + path.write_text(json.dumps(payload, sort_keys=True), encoding="utf-8") + + def write_project_status( + self, + status: str, + *, + include_target: bool, + consistent: bool = True, + ) -> None: + worktrees = [ + { + "branch": "main", + "path": str(self.root), + } + ] + if include_target: + worktrees.append( + { + "branch": f"worktree-{TASK}", + "path": str(self.target), + } + ) + payload = { + "active_arcs": [], + "consistency": { + "errors": [] if consistent else ["fixture inconsistency"], + "ok": consistent, + "warnings": [], + }, + "freshness": { + "ledgers": True, + "work_orders": True, + }, + "runs": [ + { + "agent_id": AGENT_ID, + "id": TASK, + "phase": "check-land" if status == "running" else "site-publish", + "status": status, + "worktree": str(self.target), + } + ], + "worktrees": worktrees, + } + self.status_json.write_text(json.dumps(payload, sort_keys=True), encoding="utf-8") + + def write_page(self, source: str, message: str) -> None: + (self.pages / "index.html").write_text( + "" + f"{TITLE}" + f'' + "\n", + encoding="utf-8", + ) + git(self.pages, "add", "index.html") + git(self.pages, "commit", "-q", "-m", message) + git(self.pages, "push", "-q", "origin", "HEAD:pages") + + def land(self, *, cleanup: bool = True, page_source: str | None = None) -> None: + git(self.root, "merge", "-q", "--ff-only", f"worktree-{TASK}") + git(self.root, "push", "-q", "origin", "main") + git(self.root, "update-ref", "refs/remotes/origin/main", self.revision) + self.write_page(page_source or self.revision, "fixture candidate pages") + if cleanup: + git(self.root, "worktree", "remove", str(self.target)) + git(self.root, "branch", "-D", f"worktree-{TASK}") + self.write_project_status("ok", include_target=False) + else: + self.write_project_status("running", include_target=True) + + def observe( + self, + *, + root: Path | None = None, + gate: Path | None = None, + channel: Path | None = None, + deployment: Path | None = None, + extra_env: dict[str, str] | None = None, + ) -> subprocess.CompletedProcess[str]: + env = os.environ.copy() + env.update( + { + "AGENT_ID": AGENT_ID, + "OBSERVER_STATUS_JSON": str(self.status_json), + } + ) + if extra_env: + env.update(extra_env) + command = [ + sys.executable, + str(OBSERVER), + "--root", + str(root or (self.target if self.target.exists() else self.root)), + "--task", + TASK, + "--revision", + self.revision, + "--site-url", + "https://example.invalid/misaligned/", + "--gate-receipt", + str(gate or self.gate_receipt), + ] + if channel is not None: + command.extend(["--channel-receipt", str(channel)]) + if deployment is not None: + command.extend(["--deployment-receipt", str(deployment)]) + return subprocess.run( + command, + cwd=root or (self.target if self.target.exists() else self.root), + env=env, + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + check=False, + ) + + +class IntegrationTests(unittest.TestCase): + def test_ready_receipt_is_byte_stable_and_does_not_touch_observed_git(self) -> None: + with tempfile.TemporaryDirectory() as raw_tmp: + fixture = LandingFixture(Path(raw_tmp)) + before = filesystem_fingerprint(fixture.base) + first = fixture.observe() + middle = filesystem_fingerprint(fixture.base) + second = fixture.observe() + after = filesystem_fingerprint(fixture.base) + + self.assertEqual(first.returncode, 0, first.stderr) + self.assertEqual(second.returncode, 0, second.stderr) + self.assertEqual(first.stdout, second.stdout) + self.assertEqual(before, middle) + self.assertEqual(before, after) + receipt = json.loads(first.stdout) + self.assertEqual(receipt["schema"], landing_observer.SCHEMA) + self.assertEqual(receipt["state"], "ready") + self.assertEqual(receipt["exact_revision"], fixture.revision) + self.assertEqual(codes(receipt["missing_steps"]), {"land_candidate"}) + self.assertEqual(receipt["anomalies"], []) + self.assertEqual(receipt["evidence"]["target_worktree"]["present"], True) + + def test_completed_landing_reads_cleaned_path_and_exact_receipts(self) -> None: + with tempfile.TemporaryDirectory() as raw_tmp: + fixture = LandingFixture(Path(raw_tmp)) + fixture.land() + fixture.write_receipt( + fixture.channel_receipt, + channel_payload(fixture.revision), + ) + before = filesystem_fingerprint(fixture.base) + observed = fixture.observe(channel=fixture.channel_receipt) + after = filesystem_fingerprint(fixture.base) + + self.assertEqual(observed.returncode, 0, observed.stderr) + self.assertEqual(before, after) + self.assertFalse(fixture.target.exists()) + receipt = json.loads(observed.stdout) + self.assertEqual(receipt["state"], "landed") + self.assertEqual(receipt["missing_steps"], []) + self.assertEqual(receipt["anomalies"], []) + self.assertEqual(receipt["evidence"]["target_worktree"]["present"], False) + self.assertEqual( + receipt["evidence"]["pages"]["source_revision"], + fixture.revision, + ) + + def test_remote_pages_can_prove_landing_while_public_edge_lags(self) -> None: + with tempfile.TemporaryDirectory() as raw_tmp: + fixture = LandingFixture(Path(raw_tmp)) + fixture.land() + fixture.write_receipt( + fixture.channel_receipt, + channel_payload(fixture.revision), + ) + observed = fixture.observe( + channel=fixture.channel_receipt, + extra_env={ + "OBSERVER_PUBLIC_SOURCE": ZERO_SHA, + "OBSERVER_SMOKE_FAIL": "1", + }, + ) + + self.assertEqual(observed.returncode, 0, observed.stderr) + receipt = json.loads(observed.stdout) + self.assertEqual(receipt["state"], "landed") + self.assertEqual(codes(receipt["anomalies"]), {"public_edge_converging"}) + self.assertEqual( + receipt["evidence"]["public_site"]["source_revision"], + ZERO_SHA, + ) + + def test_deployment_receipt_conflict_is_inconsistent(self) -> None: + with tempfile.TemporaryDirectory() as raw_tmp: + fixture = LandingFixture(Path(raw_tmp)) + fixture.land() + fixture.write_page(fixture.base_revision, "fixture stale pages") + fixture.write_receipt( + fixture.deployment_receipt, + deployment_payload(fixture.revision, status="pass"), + ) + observed = fixture.observe(deployment=fixture.deployment_receipt) + self.assertEqual(observed.returncode, 2, observed.stderr) + receipt = json.loads(observed.stdout) + self.assertEqual(receipt["state"], "inconsistent") + self.assertIn( + "deployment_receipt_conflicts_with_pages", + codes(receipt["anomalies"]), + ) + + def test_recorded_target_path_cannot_escape_into_primary_checkout(self) -> None: + with tempfile.TemporaryDirectory() as raw_tmp: + fixture = LandingFixture(Path(raw_tmp)) + nested = fixture.root / ".letta" / "worktrees" / TASK + git(fixture.root, "worktree", "remove", str(fixture.target)) + nested.mkdir(parents=True) + fixture.write_project_status("running", include_target=False) + payload = json.loads(fixture.status_json.read_text()) + payload["runs"][0]["worktree"] = str(nested) + fixture.status_json.write_text(json.dumps(payload, sort_keys=True)) + observed = fixture.observe(root=fixture.root) + receipt = json.loads(observed.stdout) + self.assertEqual(observed.returncode, 2, observed.stderr + observed.stdout) + self.assertIn("target_path_escaped", codes(receipt["anomalies"])) + + def test_stale_gate_and_project_contradiction_are_inconsistent(self) -> None: + with tempfile.TemporaryDirectory() as raw_tmp: + fixture = LandingFixture(Path(raw_tmp)) + stale_gate = fixture.base / "stale-gate.json" + fixture.write_receipt(stale_gate, gate_payload(fixture.base_revision)) + fixture.write_project_status("running", include_target=True, consistent=False) + before = filesystem_fingerprint(fixture.base) + observed = fixture.observe(gate=stale_gate) + after = filesystem_fingerprint(fixture.base) + + self.assertEqual(observed.returncode, 2, observed.stderr) + self.assertEqual(before, after) + receipt = json.loads(observed.stdout) + self.assertEqual(receipt["state"], "inconsistent") + self.assertEqual( + codes(receipt["anomalies"]), + {"gate_revision_mismatch", "project_status_inconsistent"}, + ) + + def test_dirty_primary_is_only_an_ownership_warning_after_cleanup(self) -> None: + with tempfile.TemporaryDirectory() as raw_tmp: + fixture = LandingFixture(Path(raw_tmp)) + fixture.land() + fixture.write_receipt( + fixture.channel_receipt, + channel_payload(fixture.revision), + ) + (fixture.root / "unrelated.txt").write_text("unrelated\n", encoding="utf-8") + observed = fixture.observe(channel=fixture.channel_receipt) + + self.assertEqual(observed.returncode, 0, observed.stderr) + receipt = json.loads(observed.stdout) + self.assertEqual(receipt["state"], "landed") + self.assertEqual( + codes(receipt["ownership_warnings"]), + {"unrelated_primary_checkout_dirty"}, + ) + + +if __name__ == "__main__": + unittest.main() diff --git a/wiki/log/2026-08-12-one-shot-landing-observer.md b/wiki/log/2026-08-12-one-shot-landing-observer.md new file mode 100644 --- /dev/null +++ b/wiki/log/2026-08-12-one-shot-landing-observer.md @@ -0,0 +1,69 @@ +# One-shot landing observation without a second landing authority + +``` +Type: log +``` + +## Why + +A successful landing leaves evidence at several addresses: the exact candidate, +remote `main`, remote `pages`, the public edge, project-operation state, cleanup, +and any explicit gate, deployment, or channel receipts. Reading those surfaces by +hand could confuse an ordinary stale edge with a broken landing, trust mutable local +tracking refs, or let an interpretive agent quietly become another source of landing +truth. + +The observer needed to answer one narrow question once: does one exact candidate +cohere across the authorities the existing landing workflow already owns? It must be +able to explain uncertainty without acquiring any channel that could change the +answer. + +## Implemented + +- Added the registered `observing-misaligned-landings` repository skill and a + deterministic Python observer. It requires an exact revision and task id, samples + remote `main` and `pages` twice, fetches only into a disposable bare repository, + inspects the isolated page bytes, reads offline project status and optional exact + receipts, performs one public smoke read, and emits one byte-stable JSON receipt. +- The classifier has only `ready`, `blocked`, `landed`, and `inconsistent` states. + Unknown evidence fails closed. A later coherent `main` descendant preserves the + historical landing, while a lagging public edge remains a named benign anomaly + behind the authoritative remote `pages` snapshot. +- The target and primary repositories are opened with optional Git locks disabled. + No fetch enters the project, no ref moves, and no push, deployment, notification, + schedule, repair, or cleanup channel exists. Integration fixtures fingerprint the + complete fixture filesystem before and after ready, landed, and inconsistent reads. +- Added optional anomaly interpretation through pinned + `@letta-ai/letta-agent-sdk` `0.7.1`. It finds exactly one retained specialist + named `Misaligned Landing Observer`, creates it only when absent with empty memory, + MemFS disabled, and no server tools, and fails closed on duplicate exact names. + Every anomaly read opens a fresh stateless conversation with no client tools or + skills. A strict allowlist strips paths, URLs, raw errors, and arbitrary receipt + fields before evidence crosses the repository boundary. +- The interpreter does not load the SDK for clean receipts, explicitly superseded + candidates, or public-edge convergence alone. Its output is separate and cannot + upgrade or downgrade the deterministic classification. +- Registered focused Python and Node fixtures in `tools/check.sh`; the deterministic + suite always runs, while the optional interpreter suite runs only where Node is + installed. The checked-in lockfile pins pnpm `10.20.0` and the SDK dependency. + +## Verification + +Focused classifier and repository fixtures cover coherent ready and landed states, +cleanup and receipt gaps, stale evidence, impossible project-operation combinations, +remote-ref motion, page authority, path escape, supersession, one-shot public-edge +convergence, byte stability, and whole-fixture non-mutation. Node fixtures cover +receipt minimization, benign-anomaly suppression, exact-name reuse, duplicate-name +failure, supported creation options, and fresh stateless zero-authority prompting. +The generated corpus indexes and exact project gate are the final landing checks on +the fresh reconciled candidate. + +## Not done + +This does not create gate, deployment, or channel receipts; change `tools/task.sh`; +land or repair a candidate; poll publication; or make interpretation mandatory. + +**Defense:** every effect remains on the thing that owns it. Git and project +operations produce landing truth; the deterministic observer reads exact addresses; +the optional specialist explains only minimized contradictions. No interpretive path +can acquire a mutation channel or rewrite the state it was asked to explain. diff --git a/wiki/log/DEVLOG.md b/wiki/log/DEVLOG.md --- a/wiki/log/DEVLOG.md +++ b/wiki/log/DEVLOG.md @@ -11,6 +11,11 @@ +## 2026-08-12 - One-shot landing observation without a second landing authority + +- Intent: (see session log) +- Log: [wiki/log/2026-08-12-one-shot-landing-observer.md](2026-08-12-one-shot-landing-observer.md) + ## 2026-08-11 - Territorial Personas core - Intent: (see session log) diff --git a/wiki/log/decisions.md b/wiki/log/decisions.md --- a/wiki/log/decisions.md +++ b/wiki/log/decisions.md @@ -42,3 +42,4 @@ - [2026-08-05](decisions/2026-08-05.md) - [2026-08-06](decisions/2026-08-06.md) - [2026-08-11](decisions/2026-08-11.md) +- [2026-08-12](decisions/2026-08-12.md) diff --git a/wiki/process/repository-skills.md b/wiki/process/repository-skills.md --- a/wiki/process/repository-skills.md +++ b/wiki/process/repository-skills.md @@ -40,6 +40,7 @@ | `design-companion` | `.agents/skills/design-companion/SKILL.md` | Explore and explain unsettled game-design choices in conversation without mutating the repository; hand adopted choices to `design-session`. | | `design-session` | `.agents/skills/design-session/SKILL.md`
`.claude/skills/design-session/SKILL.md` | Capture affirmed design decisions into their owning law/spec pages, decision history, and session trace. | | `playtesting-misaligned` | `.agents/skills/playtesting-misaligned/SKILL.md` | Run evidence-bearing naive and informed playtests against the current player surface and corpus. | +| `observing-misaligned-landings` | `.agents/skills/observing-misaligned-landings/SKILL.md` | Read one exact candidate across isolated remote snapshots, public/site and project-operation evidence, classify it without mutation, and optionally ask one retained exact-name, zero-tool Letta specialist in a fresh conversation to interpret only non-benign anomalies. | | `session-wrap` | `.agents/skills/session-wrap/SKILL.md`
`.claude/skills/session-wrap/SKILL.md` | Finish or preserve owned work, read exact current project state from live authorities, and report one bounded next step without maintaining a parallel checked-in handoff ledger. | | `tick` | `.agents/skills/tick/SKILL.md`
`.claude/skills/tick/SKILL.md` | Invoke the project's bounded stewardship heartbeat: audit one corpus slice, act on one finding, and leave a trace. | @@ -65,3 +66,18 @@ 5. A skill that reports current execution state reads live Git, worktree, project-status, and issue authorities; it does not maintain another tracked current-state file or hard-code one agent harness's memory tool. +6. A read-only observer fingerprints the target repository before and after the + observation, isolates remote fetches outside the repository, preserves unknown + evidence, and cannot mutate or repair the state it classifies. +7. Optional agent interpretation cannot override deterministic state. It reuses + exactly one retained `Misaligned Landing Observer` with empty memory, MemFS and + tools disabled, opens a fresh conversation over minimized evidence for each + observation, provisions only when absent, and fails closed on duplicate exact names. + +## Defense + +The landing observer is registered here because it is a checked-in operational +entry point, while the landing workflow remains owned by +[workflows.md](workflows.md#git-conventions). Keeping deterministic evidence and +optional interpretation subordinate to that law prevents a convenient observer from +becoming a second landing authority or a mutation doorway. diff --git a/wiki/process/workflows.md b/wiki/process/workflows.md --- a/wiki/process/workflows.md +++ b/wiki/process/workflows.md @@ -282,6 +282,19 @@ push. Optional later step: move the same publish into CI once a write secret exists; keep the exact source marker and smoke contract either way. +A completed landing may be checked once with the registered +`observing-misaligned-landings` skill. Its deterministic receipt samples remote +`main` and `pages` into a disposable bare repository, compares public and +project-operation evidence, and classifies the exact candidate as `ready`, `blocked`, +`landed`, or `inconsistent`. The observer is strictly read-only: it does not fetch +into the project, alter refs, push, deploy, notify, schedule, or clean worktrees. +Unknown evidence fails closed. A later coherent landing supersedes an older candidate +rather than retroactively making that older landing inconsistent. Optional Letta +interpretation is subordinate and cannot change the state. It reuses one retained +exact-name, empty-memory, zero-tool specialist but opens a fresh conversation for each +observation; duplicate exact names fail closed. +Do not poll the edge merely because its one public read still serves an older source. + Starlight is the documentation renderer. Its sync copies root `DESIGN.md` to the `/constitution/` doorway and parses `wiki/SUMMARY.md` for navigation. The Rust/check pipeline enforces structural wiki correctness through @@ -350,7 +363,8 @@ union-edit them. After sources/specs are reconciled, run the generator and take its complete output. - Spec-driven rule: functional change commits amend the owning `Type: law` - or `Type: spec` page and update affected knowledge. + or `Type: spec` page and update affected knowledge. Operational observers do + not replace those owners; their receipts are evidence, not authority. - Remote: `origin` is a Tangled knot (`tangled.org`, SSH). **Land changes by merging to `main` directly** after the appropriate scoped verification passes (full `./tools/check.sh` for Rust-impacting work; focused checks for @@ -392,3 +406,13 @@ 2. `Type: knowledge` wiki page updates (if reality changed). 3. `wiki/log/YYYY-MM-DD-topic.md` session writeup; `wiki/log/DEVLOG.md` gets the short ledger line. + +## Defense: one-shot landing evidence + +The observer reads the same exact revision and authorities already required by this +workflow, but cannot produce any landing effect. Isolated remote snapshots prevent +its proof from depending on stale local tracking refs; pre/post repository +fingerprints make the read-only boundary testable; explicit unknowns prevent missing +transport, project-status, receipt, or public evidence from becoming a false green. +Keeping agent interpretation optional and unable to override the four-state classifier +preserves the executable workflow as the only landing authority. diff --git a/.agents/skills/observing-misaligned-landings/.gitignore b/.agents/skills/observing-misaligned-landings/.gitignore new file mode 100644 --- /dev/null +++ b/.agents/skills/observing-misaligned-landings/.gitignore @@ -0,0 +1,3 @@ +node_modules/ +__pycache__/ +*.py[cod] diff --git a/.agents/skills/observing-misaligned-landings/SKILL.md b/.agents/skills/observing-misaligned-landings/SKILL.md new file mode 100644 --- /dev/null +++ b/.agents/skills/observing-misaligned-landings/SKILL.md @@ -0,0 +1,119 @@ +--- +name: observing-misaligned-landings +description: Observe one completed Misaligned landing without changing it. Use after a main/pages publication, when asked whether a landing really reached the remote and public site, or when deterministic landing evidence needs optional Trace interpretation through the Letta Agent SDK. +--- + +# Observing Misaligned Landings + +Emit one machine-readable receipt proving whether an exact revision agrees across +checked-out Git state, remote `main`, remote `pages`, the public homepage, and the +project-operation dashboard. This skill observes; it never lands, deploys, repairs, +notifies, schedules, or cleans anything. + +The binding landing and publication workflow remains +`wiki/process/workflows.md#git-conventions`. `tools/project-status.py` and +`tools/site-smoke.sh` remain the project authorities this observer composes. + +## Safety boundary + +The observer may only: + +- resolve local Git objects and refs; +- read remote refs with `git ls-remote`; +- fetch sampled remote `main`, remote `pages`, and the exact candidate into one + disposable bare repository under the system temp directory, inspect only that + isolated snapshot, then delete the repository; +- run `tools/project-status.py --json --check --offline`; +- run one `tools/site-smoke.sh` attempt against the exact revision. + +It must not fetch into the observed repository, update a ref, checkout, commit, +push, deploy, create an issue, send a message, invoke a schedule, or remove a +worktree. A failed receipt reports an anomaly and stops. It does not repair it. +Do not turn the one-shot public read into propagation polling unless Cameron asks +or an actual deployment failure is being diagnosed. + +## Emit the deterministic receipt + +Run from the exact landed checkout and name the full landed revision when it is +known: + +```bash +SKILL=.agents/skills/observing-misaligned-landings +python3 "$SKILL/scripts/observe-landing.py" \ + --root "$PWD" \ + --task landing-task-id \ + --revision fd1e6accfbe90075f67e8389b46d3bf8014c1837 \ + > /tmp/misaligned-landing.json +status=$? +python3 -m json.tool /tmp/misaligned-landing.json +``` + +`--revision` is required and must name the exact full candidate revision being +proved. `--remote` defaults to `origin`; `--site-url` defaults to the production +Misaligned URL (and respects the existing `SITE_SMOKE_URL` override). + +The command always emits its deterministic state and named evidence before exiting. +The receipt has no observation timestamp or temporary path, has sorted keys and +stable row ordering, and produces identical bytes when the observed authorities do +not change. + +The checks are deliberately stricter than a successful push: + +1. the exact candidate remains stable while observed; +2. independently sampled remote `main` and `pages` refs remain stable and match the + objects fetched into the isolated snapshot; +3. ancestry classifies the candidate as current, unlanded, or superseded rather + than treating every later `main` commit as a failed landing; +4. the isolated `pages` snapshot embeds the requested source revision plus the + homepage title contract, or honestly shows that a newer source superseded it; +5. project-operation records, generated projections, exact gate/deployment/channel + receipts, ownership, cleanup, and one public-site read agree. + +The top-level deterministic state is `ready`, `blocked`, `landed`, or +`inconsistent`. Exit `0` means `ready` or `landed`; `blocked` exits `1`, and +`inconsistent` exits `2`. Unknown or unreadable evidence is preserved and fails +closed instead of being collapsed into absence. A dirty primary checkout is an +ownership warning unless it touches the observed landing surface; a later clean +landing is reported as superseding the candidate instead of contradicting it. + +## Ask Trace only about anomalies + +Deterministic checks decide classification. Agent interpretation is optional, +supplemental, and only when non-benign anomalies remain. Ordinary public-edge +convergence and explicitly superseded landings do not invoke it by themselves. + +Install the pinned SDK once for this checked-in skill, then pass the receipt: + +```bash +pnpm --dir "$SKILL" install --frozen-lockfile +node "$SKILL/scripts/interpret-anomalies.mjs" /tmp/misaligned-landing.json +``` + +The interpreter uses `@letta-ai/letta-agent-sdk` to find exactly one retained +`letta/auto` specialist named `Misaligned Landing Observer`, provisioning it only when +absent. More than one exact-name match fails closed. The specialist stays discoverable +for exact-name reuse, with empty memory, MemFS disabled, no tools or skills, and a strict +zero-action prompt. +Each observation uses SDK `prompt()` with `stateless: true`, which opens a fresh +conversation for that retained agent rather than resuming an earlier receipt and +loads no persisted MemFS state. Only minimized evidence +crosses the repository boundary: local paths, remote URLs, task paths, and raw read +errors are removed. Interpretation may explain likely convergence, stale evidence, or +project-operation inconsistency, but cannot alter the receipt or its deterministic +state. + +If no non-benign anomaly remains, the interpreter returns `status: not-needed` +without loading the SDK or contacting Letta. If credentials, SDK installation, exact +agent lookup/provisioning, or prompting fail, report interpretation failure +separately; never downgrade or upgrade the deterministic landing result. + +## Verify changes to this skill + +```bash +python3 tools/test_landing_observer.py +node --test .agents/skills/observing-misaligned-landings/tests/*.test.mjs +``` + +The fixture proves byte-stable clean receipts, exact anomaly codes, optional-SDK +fail-closed behavior, and that observing leaves the target repository's Git bytes +unchanged. diff --git a/.agents/skills/observing-misaligned-landings/package.json b/.agents/skills/observing-misaligned-landings/package.json new file mode 100644 --- /dev/null +++ b/.agents/skills/observing-misaligned-landings/package.json @@ -0,0 +1,14 @@ +{ + "name": "@misaligned/landing-observer", + "version": "1.0.0", + "private": true, + "type": "module", + "packageManager": "pnpm@10.20.0", + "scripts": { + "interpret": "node scripts/interpret-anomalies.mjs", + "test": "node --test tests/*.test.mjs" + }, + "dependencies": { + "@letta-ai/letta-agent-sdk": "0.7.1" + } +} diff --git a/.agents/skills/observing-misaligned-landings/pnpm-lock.yaml b/.agents/skills/observing-misaligned-landings/pnpm-lock.yaml new file mode 100644 --- /dev/null +++ b/.agents/skills/observing-misaligned-landings/pnpm-lock.yaml @@ -0,0 +1,3065 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + dependencies: + '@letta-ai/letta-agent-sdk': + specifier: 0.7.1 + version: 0.7.1(ink@7.1.1(react@18.2.0))(react-dom@19.2.8(react@18.2.0))(zod@4.4.3) + +packages: + + '@alcalzone/ansi-tokenize@0.3.0': + resolution: {integrity: sha512-p+CMKJ93HFmLkjXKlXiVGlMQEuRb6H0MokBSwUsX+S6BRX8eV5naFZpQJFfJHjRZY0Hmnqy1/r6UWl3x+19zYA==} + engines: {node: '>=18'} + + '@anthropic-ai/sdk@0.91.1': + resolution: {integrity: sha512-LAmu761tSN9r66ixvmciswUj/ZC+1Q4iAfpedTfSVLeswRwnY3n2Nb6Tsk+cLPP28aLOPWeMgIuTuCcMC6W/iw==} + hasBin: true + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + zod: + optional: true + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + resolution: {integrity: sha512-u+NT61JZEkRFtpL0CAw1N1dwxnaLgwVXQl/zjJxTGgLyS/jTIdg2SdoEoCTHxgDyCnqa1HEi9QOoE9/pYRNpOQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.977.7': + resolution: {integrity: sha512-I88Iov89NVmjSmJLKSv7Cn9M2J+a2942OkA8nZCbz+sl4ZeY4zEOcoLOrbt1GRfQ8zEQKnjAJdXixA3J/p1fDQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.68': + resolution: {integrity: sha512-2a20A/IdNOwUvaDq91iqqS7BA0XlNMfW3iLGZGZLJv0EbUqhSxB0PIx4rQQqssvWj1uXImb3/UCCdHz/+1dOiA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.70': + resolution: {integrity: sha512-0yRem2Fs52r/Nn6UAqIlpjexfaYj8ziEozOe9tamtAVT/5bzFLKx8O2r7MaRqgS3hGKHIa1Jij9nKHSsNnb04A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.973.13': + resolution: {integrity: sha512-2M39DE02XpYYaSWYk/4AsImXYUU/1L2xmTMLUpMMWq7DfLv191/vCRy3baKtdr45AkJQyVgSjmuVOLm15SwrRQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.75': + resolution: {integrity: sha512-jaTESuJlQsoUZ44f/i2puyPt8VlF/dMMJ9HM3cStYtk7eKX4N9UWi83OLixUkoOJH3BwWlPLCq9YIK9nfWhVBg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.79': + resolution: {integrity: sha512-RIw5dof1EHkWubrZzPC941CDtnFG1iAXsxbFgLkhdYZXHc4icU13c/uxSMI0J5eUx9bxa7LjfpdjfClBB1QsDA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.68': + resolution: {integrity: sha512-nLP3Pda2MQTFJ25hKBMmUuB9Uv+bTZQNlufbeCwklP549Vwnkd8bRLJoCKp5k6xjmdyptrPrOfGOhN0mKuca8A==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.973.12': + resolution: {integrity: sha512-EmgyyHn+f9WCcelp3L/vci+LGbX8GigWaVphRArjVo5Pktkr9YnLy/mQ6VDkDyBD72dtfRNTgHmD2ts4rTDXKQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.74': + resolution: {integrity: sha512-0YfczxGXF3RjGj8z7QG/Ho2HnLGKDHfPSHiTs47UU1U/+mmwISDN+rvGKt2zh+3FX8NdT4xd95LGBGyhQw2dgQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/eventstream-handler-node@3.972.32': + resolution: {integrity: sha512-rlbmsMG7ZNgrVhWSqqXpq6y9hfiREyzCg3CNTk9UK+AoP7+65kOkqpWmqwLfV1UrRSHATdLnZF2rt9ZTUxYQJA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-eventstream@3.972.27': + resolution: {integrity: sha512-M7Ay1VpBpf/YFfic9kkjwE3wyCh4G0gEM4RypRXYm7aPjyfqi+D8FEYMR2E3IqbvN+qi2rEFYAiwWL0XHtQYdQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/middleware-websocket@3.972.50': + resolution: {integrity: sha512-gdcWRbmIf1dWA/prf44Bnnzgqj+AbsXX2yfhZhOQLwSm7NfKIYPmkRlPqP0CTepHzjxMIBdWBDdtQB+Y/dFUeg==} + engines: {node: '>= 14.0.0'} + + '@aws-sdk/nested-clients@3.997.42': + resolution: {integrity: sha512-XWRyon2MTHXD/zMoo0Mbge6Vwf+iE0qQaM/RyGO6NfZ9WukCFiQL27nQVZjYy2JwSIg+iXZxKOX95OBXqlSM4w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.44': + resolution: {integrity: sha512-ZSfQ35Qn4MhSY+A0Whyr+KBx+wJKZUyBsOrjB2pSHOafRzbFe47T8XcXM8hZqUAC69qnqIy0C9ArxTuud0CC2w==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1048.0': + resolution: {integrity: sha512-k0y/GcuesuSfWyUM0WamrGyeZmltRYaPbHO82UDA6mZ/doB+FOHKutikPAtSXMn/hDz970cF+iRuuiYO9VEbAA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1108.0': + resolution: {integrity: sha512-rI80zxDxGJ6904eC/YbjkdjY6JdaZvQ01kOmrMvw7cFQGIHo27fhnIVbMSVDS4T6foQImjxYSRoOu/uSJscXDw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.974.3': + resolution: {integrity: sha512-ECAqfpNsef+7MO8qtR0h9KcFIBAygaE7Cm6UOiQl+ft+uVap+1G7bNEjs4mdJE2OnA4m6k7i8peH8uGIAsOMGw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.9': + resolution: {integrity: sha512-wB/ho7pTJKqWz3WYDt2ZWDWI8bxQpN/xwf+5ZQ1zWaj+HDY9B8Fn434i6qZ6j6ZG3aCiIJtZaQVqwajx5xYsQA==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.38': + resolution: {integrity: sha512-grf7mzfVxBS5AlsuTvBN7uDpzqohFww9fRPCO+EBSUdvtsYMcPSKdz54h/7XiscqNcUM1Ae1MF7JLHmiYYuzbQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.3.0': + resolution: {integrity: sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==} + engines: {node: '>=18.0.0'} + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@earendil-works/pi-ai@0.82.1': + resolution: {integrity: sha512-3WFYRhEp3lQB3444EhPMBcM7zSaEUE3eJgHOR7s4081NLqbw/FsWilIKWXSua0Gv3sRr7m9xMidR3pPDE7jI/A==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} + + '@google/genai@1.52.0': + resolution: {integrity: sha512-gwSvbpiN/17O9TbsqSsE/OzZcpv5Fo4RQjdngGgogtuB9RsyJ8ZHhX5KjHj1bp5N9snN2eK8LDGXSaWW2hof8Q==} + engines: {node: '>=20.0.0'} + peerDependencies: + '@modelcontextprotocol/sdk': ^1.25.2 + peerDependenciesMeta: + '@modelcontextprotocol/sdk': + optional: true + + '@hono/node-server@2.1.0': + resolution: {integrity: sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==} + engines: {node: '>=20'} + peerDependencies: + hono: ^4 + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@letta-ai/letta-agent-sdk@0.7.1': + resolution: {integrity: sha512-pwzEzBwTtqj88Z8uRNmU/mRor5N57Sbzcz0dKT3t284kQWNwQDvBrhPeDVdh+Z1ARZOSY4BKrIcthiv30RhwEA==} + engines: {node: '>=22.19.0'} + + '@letta-ai/letta-client@1.12.1': + resolution: {integrity: sha512-rYjXMXpkfssj7VBBX3qCp6mdpNRv6YPNrliYsjkhWoQDqGg3J9bsgIQ28ZhQTddabYxRUIwcdzuaizFx8pvZ7A==} + + '@letta-ai/letta-code@0.30.11': + resolution: {integrity: sha512-BPnpFVnCC0YinSu/LUKlzZur94pVPMytrUT4Qv8mGknJE77t15vNcALhspq+bESu2Lj67ZaQ6n2FgIy9dwmteQ==} + engines: {node: '>=22.19.0'} + hasBin: true + + '@letta-ai/trajectory@0.2.0': + resolution: {integrity: sha512-biCyT0z8nh4Q8kIqBrPgmzoalacPmosmCpvEjdN9ILpL85+T75b8ahcN9MHPHQUVRj/J7UyQuRahJ4/JdrpCcA==} + engines: {node: '>=20'} + + '@mistralai/mistralai@2.2.6': + resolution: {integrity: sha512-W8pX7zHxjJvMIpw8JMxeJEleapXX0Q9NPszdNzqkM3MIEoIGPObdodujj+WHteXEvGfaP/AMwlNyRfEzSY6dQQ==} + peerDependencies: + '@opentelemetry/api': ^1.9.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + + '@modelcontextprotocol/sdk@1.30.0': + resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} + engines: {node: '>=18'} + peerDependencies: + '@cfworker/json-schema': ^4.1.1 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@cfworker/json-schema': + optional: true + + '@opentelemetry/api@1.9.0': + resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} + engines: {node: '>=8.0.0'} + + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} + engines: {node: '>=14'} + + '@pierre/diffs@1.2.2': + resolution: {integrity: sha512-MvWLv2oSOJOF8oYXWLdhicguHM11G/VNWu6OPR5ZETolp2NM2/KPQG3cZTnKpJ6ImqEHwvw6Gl6z2gmmy2FQmQ==} + peerDependencies: + react: ^18.3.1 || ^19.0.0 + react-dom: ^18.3.1 || ^19.0.0 + + '@pierre/theme@1.0.3': + resolution: {integrity: sha512-sWHv11TMoqKxKDgTIk5VbhQjdPhs8DCcBxbjh3mRlS3YOM/OcrWoGX6MM8eBGn9cUu3M46Py0JnxsG2nJaFTuA==} + engines: {vscode: ^1.0.0} + + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.5': + resolution: {integrity: sha512-zgXFLzW3Ap33e6d0Wlj4MGIm6Ce8O89n/apUaGNB/jx+hw+ruWEp7EwGUshdLKVRCxZW12fp9r40E1mQrf/34g==} + + '@protobufjs/eventemitter@1.1.1': + resolution: {integrity: sha512-vW1GmwMZNnL+gMRaovlh9yZX74kc+TTU3FObkkurpMaRtBfLP3ldjS9KQWlwZgraRE0+dheEEoAxdzcJQ8eXZg==} + + '@protobufjs/fetch@1.1.1': + resolution: {integrity: sha512-GpptLrs57adMSuHi3VNj0mAF8dwh36LMaYF6XyJ6JMWlVsc+t42tm1HSEDmOs3A8fC9yyeisgLhsTVQokOZ0zw==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.2': + resolution: {integrity: sha512-b1UQwcEZ4yCnMCD8DAL1VlbvBJE9/IX4FTIp7BG1xYpf29SLazLSrqUkj4w7Y5y7cCVP6E5tcqqcI0xemPkHug==} + + '@scarf/scarf@1.4.0': + resolution: {integrity: sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==} + + '@shikijs/core@3.23.0': + resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} + + '@shikijs/core@4.4.3': + resolution: {integrity: sha512-QCR4q2ZO/ILJEuwiBMel4wdcTDb1JGwfjKTxPDF6x8ixOaluPrVqIn06C99AcRPhmYlBR56d/Fb+GN58GzExpg==} + engines: {node: '>=20'} + + '@shikijs/engine-javascript@3.23.0': + resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} + + '@shikijs/engine-javascript@4.4.3': + resolution: {integrity: sha512-FbOjFJp9VLdo1Wevs10BBtVxiTWwNLqZh5Gkhjgda/ioL15YOgeSl9n+6XMa3qRlPQzfhFNe641SrynFHYG0nQ==} + engines: {node: '>=20'} + + '@shikijs/engine-oniguruma@3.23.0': + resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} + + '@shikijs/engine-oniguruma@4.4.3': + resolution: {integrity: sha512-EcOQkxdxGQrc1Row/cC2c96/v1dbZqGnEVu1qTuT/MJmp6+cXCvQussowVmCv5Tqr3KuY3c7IbM6HTW3LJ1k9w==} + engines: {node: '>=20'} + + '@shikijs/langs@3.23.0': + resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} + + '@shikijs/langs@4.4.3': + resolution: {integrity: sha512-ePic0yfAJGOF83D5wBHK/00EjK65oahBYxFk5epgq33WRv7X9UuxLEV8PtR0szC0z8dl7INIpIodB99JRFlR+A==} + engines: {node: '>=20'} + + '@shikijs/primitive@4.4.3': + resolution: {integrity: sha512-m0wBeLDQDeIxRdUmrCPdQqfuUamDwRL5isCfYbguKD6NiaKpVbsv+3J81DyIKgNW5h4WAIIr8T4EkgQrBBxvaQ==} + engines: {node: '>=20'} + + '@shikijs/themes@3.23.0': + resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + + '@shikijs/themes@4.4.3': + resolution: {integrity: sha512-w8UHjeUnIR965KMWJHUPXOc2mNJUnK3vpVLYLvw5IYU2mnTTJ89E24OrJDBNiJDQ0qzb0tc4l7mrIXx5cFeIyw==} + engines: {node: '>=20'} + + '@shikijs/transformers@3.23.0': + resolution: {integrity: sha512-F9msZVxdF+krQNSdQ4V+Ja5QemeAoTQ2jxt7nJCwhDsdF1JWS3KxIQXA3lQbyKwS3J61oHRUSv4jYWv3CkaKTQ==} + + '@shikijs/types@3.23.0': + resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} + + '@shikijs/types@4.4.3': + resolution: {integrity: sha512-UEJxmRR++MAGR6hugn0vgVS2W/6lWAts84FFSrnlH9sP0LNol7E5+NQ792pH8liWUhyMyjhTgSUH3k7iD7tc5g==} + engines: {node: '>=20'} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@smithy/core@3.32.0': + resolution: {integrity: sha512-NAiCSC78fzbNIEWoheoF74Ob5ZorLijCHpMY26Fqvqg/+9LuyIqMfHDg2p8Yk1rqOyowtiL3y7WX0AW+teL6zw==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.5.0': + resolution: {integrity: sha512-2jsPi+7Zv2hSzD9IXR9D7DTqSn7mv4XalzRm+bESh53jiaUS3NKEUbpQFTJP0HhQy9qzZvluxQ3yS24zdRrqsA==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.7.0': + resolution: {integrity: sha512-W/exA8T0LEzCQtJ02w4IzaEQPIspgarqZprb7W8FwnYiDowgCrjl2fTQ6FvuSSUnJORuepBF81abmBJwqh+0XQ==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.10.0': + resolution: {integrity: sha512-nrh7VxqzPQS/ip1hS293aI/OAWDWARQvjUxCfuKhyrfHa2gTdk28066RNeWLI1uuoHXaKAkOF8IcSAHuOp0+SA==} + engines: {node: '>=18.0.0'} + + '@smithy/node-http-handler@4.7.3': + resolution: {integrity: sha512-/jPhevcTFPMVl6KNjbaI47iOg1zxC7IsnX4PQDGVZKMFceOXtB8IEYaB7a9VvkP/3oC60WzTeKocvSI7vLT0vA==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.7.0': + resolution: {integrity: sha512-hCynhm22wMJ8wTF9crcwu8mxggtUrSLLJgDcGUvYFBqpofxycYJCGKOMYg4xtPPFtgNiDJSYmhsWLTrcU/g59Q==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.17.0': + resolution: {integrity: sha512-Aw4joiM0ZdErpo39lCj8phT2lxoiKZV+KZzBxnnQhWVtU2Is/WffQSL04uUWRcXUse9Ln8vXZK6V/FwqRVnQpg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@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/node@26.2.0': + resolution: {integrity: sha512-5IviulTZeRNp2vAJ514cc/HUlY5nZ9fCbq9DMyC52BrhFZACo3nI0R7qBxhQmo/d27NFe96ur/b7Wwxklda+kg==} + + '@types/retry@0.12.0': + resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@ungap/structured-clone@1.3.3': + resolution: {integrity: sha512-60YRaenCQcVjYEKOcG824+DRGGIQ3VKErcBoAEDJZz5bKIs2ZG+X/H9Nk+Q6EVkwJk5QNApxbrc5QtBSwtrXAg==} + + '@vscode/ripgrep-darwin-arm64@1.18.0': + resolution: {integrity: sha512-r3ktHSvbFycQNF6sl7sNDPocpsI7J+mEzh1IaZFkY0spm3k2Z9t8hPAeOK7+p0l6p6/swkQC14XWX01low+94Q==} + cpu: [arm64] + os: [darwin] + + '@vscode/ripgrep-darwin-x64@1.18.0': + resolution: {integrity: sha512-25b4gWbL138dGuQU244ebCKKc0q05ULBMoFSz9oAEUHNeqK/lOJViDS7DRvbDazzAzSEdan391Znks/R5mkaTQ==} + cpu: [x64] + os: [darwin] + + '@vscode/ripgrep-linux-arm64@1.18.0': + resolution: {integrity: sha512-lQ/5zTG++U0E3IhVgS4EPTTn/U4okncaRMM5GOFfOYZywS4nuD31GhkHbNYlDk5CuDC68+hYJ0/eQeyCKJDA+g==} + cpu: [arm64] + os: [linux] + + '@vscode/ripgrep-linux-arm@1.18.0': + resolution: {integrity: sha512-GDAvufNDHu8zqLEmXstalQF0Wh6wQvdsBi/Vg3Yi3CK4a8XoFXqqXVEHEZ9xQz3t0NfoSEc9JbvK9DDS6FxyxQ==} + cpu: [arm] + os: [linux] + + '@vscode/ripgrep-linux-ia32@1.18.0': + resolution: {integrity: sha512-YWLkSUtFd4Jh5EepIhA9RJSfv3uMAVMo+2rBIGHPBnvgLrZciIs2cDKei1/p6Wc/aCzUoHyMAg2R6tw4ZCBKGg==} + cpu: [ia32] + os: [linux] + + '@vscode/ripgrep-linux-ppc64@1.18.0': + resolution: {integrity: sha512-quXVY8fwQ8O/lvU1yrSqSl3jlUzysRSb+AfUfCL/tRtphxsKlFvPAejryZ6vg4Bgvn8XL74xb4qMCDmWgYrT5w==} + cpu: [ppc64] + os: [linux] + + '@vscode/ripgrep-linux-riscv64@1.18.0': + resolution: {integrity: sha512-f5kBQBrWfQt8Q7OhSORuNDei5dkYagBj3y4jImSUXGMy8B/Ke7SltSRcUtjPv166FAFfHCAmWuZp3+cWnX2/Vw==} + cpu: [riscv64] + os: [linux] + + '@vscode/ripgrep-linux-s390x@1.18.0': + resolution: {integrity: sha512-rTOcJFGGcl2c07RUOWUo4U1ndnemKhY6A9hnMB18uk7jSgJc0d/QLBGWMWpumdtoJtpizn/wIv5mXIisJukusQ==} + cpu: [s390x] + os: [linux] + + '@vscode/ripgrep-linux-x64@1.18.0': + resolution: {integrity: sha512-mQ3bVrUpnD2vs7QT0vX90Lt0cnUq467uFtEktIdsJJmW296RoSULRGqWgzG1AKxyBpNDD6l4ZO4qKf6SgyC23Q==} + cpu: [x64] + os: [linux] + + '@vscode/ripgrep-win32-arm64@1.18.0': + resolution: {integrity: sha512-vfTIjq1OHnzUjxZcHVQAMbnggp8dpGf+0QKFOZHwWPqFwXxQC8eCWM+5NUdoJ6yrElCeMzoUTXoK/LdZaniB+Q==} + cpu: [arm64] + os: [win32] + + '@vscode/ripgrep-win32-ia32@1.18.0': + resolution: {integrity: sha512-//rfAE+BOw5AC2EMmepmiE36jUuevtQYNQqqlw1s3m9FlRxjxEut97RkRPHAu9BG4mSojatZx+kXZXNdyI9caQ==} + cpu: [ia32] + os: [win32] + + '@vscode/ripgrep-win32-x64@1.18.0': + resolution: {integrity: sha512-KNPvtElldqILHdnAetujPaowkNbpqJy3ssIGGN6F6Kve9Qi+nNLI2DN01O83JjCEVQbCzl8Ov3QZ9Eov3BR8Dg==} + cpu: [x64] + os: [win32] + + '@vscode/ripgrep@1.18.0': + resolution: {integrity: sha512-ns5lWe44tSfbTMbVUsyB+I1819PVSw4AdpgK0RNkzfWfwy6+3IUNSxwSrfTno1/oWaS/hERNz+XLWVyga2aJBQ==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + ansi-escapes@7.3.0: + resolution: {integrity: sha512-BvU8nYgGQBxcmMuEeUEmNTvrMVjJNSH7RgW24vXexN4Ven6qCvy4TntnvlnwnMLTVlcRQQdbRY8NKnaIoeWDNg==} + engines: {node: '>=18'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + auto-bind@5.0.1: + resolution: {integrity: sha512-ooviqdwwgfIfNmDwo94wlshcdzfO64XV0Cg6oDsDYBJfITDz1EngD2z7DkbvCWn+XIMsIqW27sEVF6qcpJrRcg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} + engines: {node: '>=18'} + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + + brace-expansion@5.0.9: + resolution: {integrity: sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==} + engines: {node: 20 || >=22} + + buffer-equal-constant-time@1.0.1: + resolution: {integrity: sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==} + + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + 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==} + + cli-boxes@4.0.1: + resolution: {integrity: sha512-5IOn+jcCEHEraYolBPs/sT4BxYCe2nHg374OPiItB1O96KZFseS2gthU4twyYzeDcFew4DaUM/xwc5BQf08JJw==} + engines: {node: '>=18.20 <19 || >=20.10'} + + cli-cursor@4.0.0: + resolution: {integrity: sha512-VGtlMu3x/4DOtIUwEkRezxUZ2lBacNJCHash0N0WeZDBS+7Ux1dm3XWAgWYxLJFMMdOeXMHXorshEFhbMSGelg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cli-truncate@6.1.1: + resolution: {integrity: sha512-06p9vyLahLa4zkGcgsGxU6iEkSOiuI4fhCH6Emhe2lPAcoUv73n72DnODsnHA+5wwXGnV0n9M9/qOQJSjYhFhw==} + engines: {node: '>=22'} + + code-excerpt@4.0.0: + resolution: {integrity: sha512-xxodCmBen3iy2i0WtAK8FlFNrRzjUqjRsMfho58xT/wvZU1YTM3fCnRjcy1gJPMepaRlgm/0e6w8SpWHpn3/cA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} + engines: {node: '>=18'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + content-type@2.0.0: + resolution: {integrity: sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==} + engines: {node: '>=18'} + + convert-to-spaces@2.0.1: + resolution: {integrity: sha512-rcQ1bsQO9799wq24uE5AM2tAILy4gXGIK/njFWcVQkGNZ96edlpY+A7bjwvzjYvLDyzmG1MmMLZhpcsb+klNMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} + engines: {node: '>= 0.10'} + + cron-parser@5.8.1: + resolution: {integrity: sha512-fVw5nGEkTVmiPKo3fY0j28Thq6jR00VKWyL22llWrsbII4sDHI+8Kx1kcL+QzGQJfCfk64bbMotrgTZRpzYpLQ==} + engines: {node: '>=18'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + data-uri-to-buffer@4.0.1: + resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} + engines: {node: '>= 12'} + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.0: + resolution: {integrity: sha512-H9LMLr5zwIbSxrmvikGuI/5KGhZ8E2zH3stkMgM5LpOWDutGM2JZaj460Udnf1a+946zc7YBgrqEWwbk7zHvGw==} + engines: {node: '>=18'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + 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==} + + diff@8.0.3: + resolution: {integrity: sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==} + engines: {node: '>=0.3.1'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ecdsa-sig-formatter@1.0.11: + resolution: {integrity: sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + environment@1.1.0: + resolution: {integrity: sha512-xUtoPkMggbz0MPyPiIWr1Kp4aeWJjDZ6SMvURhimjdZgsRuDplF5/s9hcgGhyXMhs+6vpnuoiZ2kFiu3FMnS8Q==} + engines: {node: '>=18'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-toolkit@1.50.0: + resolution: {integrity: sha512-OyZKhUVvEep9ITEiwHn8GKnMRQIVqoSIX7WnRbkWgJkllCujilqP2rD0u979tkl8wqyc8ICwlc1UBVv/Sl1G6w==} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.1.1: + resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} + + express-rate-limit@8.6.2: + resolution: {integrity: sha512-YH4ru+eOJxQABscKFfRCy9R7x9QFGdezclVMwwgFFndzS2Xnm0uo6B0ABZsLhcpeptGv2qvuJVWlQr9gQZoC3A==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' + + express@5.2.1: + resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} + engines: {node: '>= 18'} + + extend@3.0.2: + resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-uri@3.1.5: + resolution: {integrity: sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==} + + fetch-blob@3.2.0: + resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} + engines: {node: ^12.20 || >= 14.13} + + finalhandler@2.1.1: + resolution: {integrity: sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==} + engines: {node: '>= 18.0.0'} + + formdata-polyfill@4.0.10: + resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} + engines: {node: '>=12.20.0'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gaxios@7.3.0: + resolution: {integrity: sha512-RB5vLV+vvQeoFPCX4QMK6/hjVkbIamPp1QSUD0CiZcnj12qbpiL+pLbYtgD+oZkWl0tl9z+o2Utp+MpM3QRhBA==} + engines: {node: '>=18'} + + gcp-metadata@8.1.2: + resolution: {integrity: sha512-zV/5HKTfCeKWnxG0Dmrw51hEWFGfcF2xiXqcA3+J90WDuP0SvoiSO5ORvcBsifmx/FoIjgQN3oNOGaQ5PhLFkg==} + engines: {node: '>=18'} + + get-east-asian-width@1.6.0: + resolution: {integrity: sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==} + engines: {node: '>=18'} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} + + google-auth-library@10.9.1: + resolution: {integrity: sha512-i1ydyHrqcIxXkWh/uBmVkzCvIuq5yiK2ATndIe5XxKholrG/MTYP9xGYka4sQhrbIAgGjL2B6NOE7rFaiF3fXw==} + engines: {node: '>=18'} + + google-logging-utils@1.1.3: + resolution: {integrity: sha512-eAmLkjDjAFCVXg7A1unxHsLf961m6y17QFqXqAXGj/gVkKFrEICfStRfwUlGNfeCEjNRa32JEWOUTlYXPyyKvA==} + engines: {node: '>=14'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + has-flag@5.0.1: + resolution: {integrity: sha512-CsNUt5x9LUdx6hnk/E2SZLsDyvfqANZSUq4+D3D8RzDJ2M+HDTIkF60ibS1vHaK55vzgiZw1bEPFG9yH7l33wA==} + engines: {node: '>=12'} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hono@4.13.1: + resolution: {integrity: sha512-kdJoFVv2xmayw6cY09H7AbMJMt8Jn5jdlEdXsP7AGBdF2DIptVlKlOLKXP41yPip4/a3yQPv9gVcJYI8YY04dw==} + engines: {node: '>=16.9.0'} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + 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'} + + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} + engines: {node: '>=0.10.0'} + + indent-string@5.0.0: + resolution: {integrity: sha512-m6FAo/spmsW2Ab2fU35JTYwtOKa2yAwXSwgjSv1TJzh4Mh7mC3lzAOVLBprb72XsTrgkEIsl7YrFNAiDiRhIGg==} + engines: {node: '>=12'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ink-link@5.0.0: + resolution: {integrity: sha512-TFDXc/0mwUW7LMjsr0/LeLxPVV5BnHDuDQff9RCgP4rb3R+V/4dIwGBZbCevcJZtQnVcW+Iz1LUrUbpq+UDwYA==} + engines: {node: '>=18'} + peerDependencies: + ink: '>=6' + + ink@7.1.1: + resolution: {integrity: sha512-Y43xxa1ZSPvpmfLHcN5o+OdP8Rf8ykkNJEuKYOUNZKT8wXVNLFTtEm1nSDMQkfBH+YANF4Xuu0hhZ4ejqAtN2w==} + engines: {node: '>=22'} + peerDependencies: + '@types/react': '>=19.2.0' + react: '>=19.2.0' + react-devtools-core: '>=6.1.2' + peerDependenciesMeta: + '@types/react': + optional: true + react-devtools-core: + optional: true + + ip-address@10.5.0: + resolution: {integrity: sha512-R5SnVLJmgYYvf2F2ZgwSBnelz5G4q5AxIC277GDfUaNbrZKNANcBC7RHqYYePlszf4kBolVkJauG0ZjHHFh55g==} + engines: {node: '>= 12'} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-fullwidth-code-point@5.1.0: + resolution: {integrity: sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==} + engines: {node: '>=18'} + + is-in-ci@2.0.0: + resolution: {integrity: sha512-cFeerHriAnhrQSbpAxL37W1wcJKUUX07HyLWZCW1URJT/ra3GyUTzBgUnh24TMVfNTV2Hij2HLxkPHFZfOZy5w==} + engines: {node: '>=20'} + hasBin: true + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jose@6.2.8: + resolution: {integrity: sha512-Bsdjwm3Qsd/P0jR+BHDe3LytDfY7WBq2HmCCLIwuVRHMuEC9ae7/R474GIUdF1NgCyZjzVo/A9DOiOBtXq8ZoQ==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + + json-schema-typed@8.0.2: + resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} + + jwa@2.0.1: + resolution: {integrity: sha512-hRF04fqJIP8Abbkq5NKGN0Bbr3JxlQ+qhZufXVr0DvujKy93ZCbXZMHDL4EOtodSbCWxOqR8MS1tXA5hwqCXDg==} + + jws@4.0.1: + resolution: {integrity: sha512-EKI/M/yqPncGUUh44xz0PxSidXFr/+r0pA70+gIYhjv+et7yxM+s29Y+VGDkovRofQem0fs7Uvf4+YmAdyRduA==} + + long@5.3.2: + resolution: {integrity: sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} + engines: {node: 20 || >=22} + + lru_map@0.4.1: + resolution: {integrity: sha512-I+lBvqMMFfqaV8CJCISjI3wbjmwVu/VyOoU7+qtu9d7ioW5klMgsTTiUOUp+DJvfTTzKXoPbyC6YfgkNcyPSOg==} + + luxon@3.7.2: + resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} + engines: {node: '>=12'} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + node-addon-api@7.1.1: + resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} + + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead + + node-fetch@3.3.2: + resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + node-pty@1.1.0: + resolution: {integrity: sha512-20JqtutY6JPXTUnL0ij1uad7Qe1baT46lyolh2sSENDd4sTzKZ4nmAFkeAARDKwmlLjPx6XKRlwRUxwjOy+lUg==} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + + open@10.2.0: + resolution: {integrity: sha512-YgBpdJHPyQ2UE5x+hlSXcnejzAvD0b22U2OuAP+8OnlJT+PjWPxtgmGqKKc+RgTM63U9gN0YzrYc71R2WT/hTA==} + engines: {node: '>=18'} + + openai@6.26.0: + resolution: {integrity: sha512-zd23dbWTjiJ6sSAX6s0HrCZi41JwTA1bQVs0wLQPZ2/5o2gxOJA5wh7yOAUgwYybfhDXyhwlpeQf7Mlgx8EOCA==} + hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true + + p-retry@4.6.2: + resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + engines: {node: '>=8'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + partial-json@0.1.7: + resolution: {integrity: sha512-Njv/59hHaokb/hRUjce3Hdv12wd60MtM9Z5Olmn+nehe0QDAsRtRbJPvJ0Z91TusF0SuZRIvnM+S4l6EIP8leA==} + + patch-console@2.0.0: + resolution: {integrity: sha512-0YNdUceMdaQwoKce1gatDScmMo5pu/tfABfnzEqeG0gtTmd7mh/WcwgUjtAeOU7N8nFFlbQBnFK2gXW5fGvmMA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} + + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} + + pkce-challenge@5.0.1: + resolution: {integrity: sha512-wQ0b/W4Fr01qtpHlqSqspcj3EhBvimsdh0KlHhH8HRZnMsEa0ea2fTULOXOS9ccQr3om+GcGRk4e+isrZWV8qQ==} + engines: {node: '>=16.20.0'} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + protobufjs@7.6.5: + resolution: {integrity: sha512-/FPD0nUc9jH6rfFjji9IBqOz4pcSE3CsT1m7Ep6Mdb0LxSUMj8hgl6GomOvZzpNpAqqGaXA0P3VSrZLFzIhQrw==} + engines: {node: '>=12.0.0'} + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + qs@6.15.3: + resolution: {integrity: sha512-O9gl3zCl5h5blw1KGUzQKhA5oUXSl8rwUIM5o0S3nCXMliSvy5Dzx7/DJcI+SwgICv+IneSZwhBh1oSyEHA71A==} + engines: {node: '>=0.6'} + + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} + engines: {node: '>= 0.6'} + + raw-body@3.0.2: + resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} + engines: {node: '>= 0.10'} + + react-dom@19.2.8: + resolution: {integrity: sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==} + peerDependencies: + react: ^19.2.8 + + react-reconciler@0.33.0: + resolution: {integrity: sha512-KetWRytFv1epdpJc3J4G75I4WrplZE5jOL7Yq0p34+OVOKF4Se7WrdIdVC45XsSSmUTlht2FM/fM1FZb1mfQeA==} + engines: {node: '>=0.10.0'} + peerDependencies: + react: ^19.2.0 + + react@18.2.0: + resolution: {integrity: sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==} + engines: {node: '>=0.10.0'} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + restore-cursor@4.0.0: + resolution: {integrity: sha512-I9fPXU9geO9bHOt9pHHOhOkYerIMsmVaWB0rA2AI9ERh/+x/i7MV5HKBNrg+ljO5eoPVgCcnFuRjJ9uH6I/3eg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + retry@0.13.1: + resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} + engines: {node: '>= 4'} + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} + engines: {node: '>=10'} + hasBin: true + + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} + engines: {node: '>= 18'} + + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shiki@3.23.0: + resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} + + shiki@4.4.3: + resolution: {integrity: sha512-Mb/GvXPHBAXdgGIcnfU5L3ldpn1XcxrGkPHwqgRx17/I2XRfqlFKk2vGkHWINn1kdXvzJZeuO3is6I9KLPFm0g==} + engines: {node: '>=20'} + + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} + engines: {node: '>= 0.4'} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + slice-ansi@9.0.0: + resolution: {integrity: sha512-SO/3iYL5S3W57LLEniscOGPZgOqZUPCx6d3dB+52B80yJ0XstzsC/eV8gnA4tM3MHDrKz+OCFSLNjswdSC+/bA==} + engines: {node: '>=22'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + string-width@8.2.2: + resolution: {integrity: sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==} + engines: {node: '>=20'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-hyperlinks@4.5.0: + resolution: {integrity: sha512-ZW2OvfeCXrNTbLakPUzjQG922EeGCOteFSVoek5DKStTh898wf7zgtuFlzQN8HfZCxC3Eh02yJVrRW51hADf+w==} + engines: {node: '>=20'} + + tagged-tag@1.0.0: + resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} + engines: {node: '>=20'} + + terminal-link@5.0.0: + resolution: {integrity: sha512-qFAy10MTMwjzjU8U16YS4YoZD+NQLHzLssFMNqgravjbvIPNiqkGFR4yjhJfmY9R5OFU7+yHxc6y+uGHkKwLRA==} + engines: {node: '>=20'} + + terminal-size@4.0.1: + resolution: {integrity: sha512-avMLDQpUI9I5XFrklECw1ZEUPJhqzcwSWsyyI8blhRLT+8N1jLJWLWWYQpB2q2xthq8xDvjZPISVh53T/+CLYQ==} + engines: {node: '>=18'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-fest@5.8.0: + resolution: {integrity: sha512-YGYEVz3Fm5iy/AybuA0oyNFq7H4CgQNfRp/qfe8nurE1kuCeNm3/vfm9X4Mtl+qLyaKJUh5xrFZwogr41SMjYA==} + engines: {node: '>=20'} + + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} + + typebox@1.1.38: + resolution: {integrity: sha512-pZ0aQPmMmXoUvSbeuWf/Hzsc+avNw/Zd6VeE8CFgkVGWyuHPJvqeJJDeJqLve+K70LvjYIoleGcoJHPT17cWoA==} + + undici-types@8.3.0: + resolution: {integrity: sha512-j375ScV60dom+YkPFIfTLcOiPxkN/buHz5GobjLhixFuANaNs3C9l4GmrWqejgXWJ7BbJcFYpTEUkS1Ge8bpZQ==} + + 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==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + web-streams-polyfill@3.3.3: + resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} + engines: {node: '>= 8'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + widest-line@6.0.0: + resolution: {integrity: sha512-U89AsyEeAsyoF0zVJBkG9zBgekjgjK7yk9sje3F4IQpXBJ10TF6ByLlIfjMhcmHMJgHZI4KHt4rdNfktzxIAMA==} + engines: {node: '>=20'} + + wrap-ansi@10.0.0: + resolution: {integrity: sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==} + engines: {node: '>=20'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} + 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 + + wsl-utils@0.1.0: + resolution: {integrity: sha512-h3Fbisa2nKGPxCpm89Hk33lBLsnaGBvctQopaBSOW/uIs6FTe1ATyAnKFJrzVs9vpGdsTe73WF3V4lIsk4Gacw==} + engines: {node: '>=18'} + + yoga-layout@3.2.1: + resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} + + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} + peerDependencies: + zod: ^3.25.28 || ^4 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alcalzone/ansi-tokenize@0.3.0': + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + '@anthropic-ai/sdk@0.91.1(zod@4.4.3)': + dependencies: + json-schema-to-ts: 3.1.1 + optionalDependencies: + zod: 4.4.3 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.974.3 + '@aws-sdk/util-locate-window': 3.965.9 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.974.3 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.974.3 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-bedrock-runtime@3.1048.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.977.7 + '@aws-sdk/credential-provider-node': 3.972.79 + '@aws-sdk/eventstream-handler-node': 3.972.32 + '@aws-sdk/middleware-eventstream': 3.972.27 + '@aws-sdk/middleware-websocket': 3.972.50 + '@aws-sdk/token-providers': 3.1048.0 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/fetch-http-handler': 5.7.0 + '@smithy/node-http-handler': 4.10.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.977.7': + dependencies: + '@aws-sdk/types': 3.974.3 + '@aws-sdk/xml-builder': 3.972.38 + '@aws/lambda-invoke-store': 0.3.0 + '@smithy/core': 3.32.0 + '@smithy/signature-v4': 5.7.0 + '@smithy/types': 4.17.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.68': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.70': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/fetch-http-handler': 5.7.0 + '@smithy/node-http-handler': 4.10.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.973.13': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/credential-provider-env': 3.972.68 + '@aws-sdk/credential-provider-http': 3.972.70 + '@aws-sdk/credential-provider-login': 3.972.75 + '@aws-sdk/credential-provider-process': 3.972.68 + '@aws-sdk/credential-provider-sso': 3.973.12 + '@aws-sdk/credential-provider-web-identity': 3.972.74 + '@aws-sdk/nested-clients': 3.997.42 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/credential-provider-imds': 4.5.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.75': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/nested-clients': 3.997.42 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.79': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.68 + '@aws-sdk/credential-provider-http': 3.972.70 + '@aws-sdk/credential-provider-ini': 3.973.13 + '@aws-sdk/credential-provider-process': 3.972.68 + '@aws-sdk/credential-provider-sso': 3.973.12 + '@aws-sdk/credential-provider-web-identity': 3.972.74 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/credential-provider-imds': 4.5.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.68': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.973.12': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/nested-clients': 3.997.42 + '@aws-sdk/token-providers': 3.1108.0 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.74': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/nested-clients': 3.997.42 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/eventstream-handler-node@3.972.32': + dependencies: + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-eventstream@3.972.27': + dependencies: + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/middleware-websocket@3.972.50': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/fetch-http-handler': 5.7.0 + '@smithy/signature-v4': 5.7.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.42': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/signature-v4-multi-region': 3.996.44 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/fetch-http-handler': 5.7.0 + '@smithy/node-http-handler': 4.10.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.44': + dependencies: + '@aws-sdk/types': 3.974.3 + '@smithy/signature-v4': 5.7.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1048.0': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/nested-clients': 3.997.42 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1108.0': + dependencies: + '@aws-sdk/core': 3.977.7 + '@aws-sdk/nested-clients': 3.997.42 + '@aws-sdk/types': 3.974.3 + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.974.3': + dependencies: + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.9': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.38': + dependencies: + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.3.0': {} + + '@babel/runtime@7.29.7': {} + + '@earendil-works/pi-ai@0.82.1(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))(ws@8.21.3)(zod@4.4.3)': + dependencies: + '@anthropic-ai/sdk': 0.91.1(zod@4.4.3) + '@aws-sdk/client-bedrock-runtime': 3.1048.0 + '@google/genai': 1.52.0(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3)) + '@mistralai/mistralai': 2.2.6(@opentelemetry/api@1.9.0) + '@opentelemetry/api': 1.9.0 + '@smithy/node-http-handler': 4.7.3 + http-proxy-agent: 7.0.2 + https-proxy-agent: 7.0.6 + openai: 6.26.0(ws@8.21.3)(zod@4.4.3) + partial-json: 0.1.7 + typebox: 1.1.38 + transitivePeerDependencies: + - '@modelcontextprotocol/sdk' + - bufferutil + - supports-color + - utf-8-validate + - ws + - zod + + '@emnapi/runtime@1.11.3': + dependencies: + tslib: 2.8.1 + optional: true + + '@google/genai@1.52.0(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))': + dependencies: + google-auth-library: 10.9.1 + p-retry: 4.6.2 + protobufjs: 7.6.5 + ws: 8.21.3 + optionalDependencies: + '@modelcontextprotocol/sdk': 1.30.0(zod@4.4.3) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@hono/node-server@2.1.0(hono@4.13.1)': + dependencies: + hono: 4.13.1 + + '@img/colour@1.1.0': {} + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.11.3 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@letta-ai/letta-agent-sdk@0.7.1(ink@7.1.1(react@18.2.0))(react-dom@19.2.8(react@18.2.0))(zod@4.4.3)': + dependencies: + '@letta-ai/letta-client': 1.12.1 + '@letta-ai/letta-code': 0.30.11(ink@7.1.1(react@18.2.0))(react-dom@19.2.8(react@18.2.0))(zod@4.4.3) + transitivePeerDependencies: + - '@cfworker/json-schema' + - bufferutil + - ink + - react-dom + - supports-color + - utf-8-validate + - zod + + '@letta-ai/letta-client@1.12.1': {} + + '@letta-ai/letta-code@0.30.11(ink@7.1.1(react@18.2.0))(react-dom@19.2.8(react@18.2.0))(zod@4.4.3)': + dependencies: + '@earendil-works/pi-ai': 0.82.1(@modelcontextprotocol/sdk@1.30.0(zod@4.4.3))(ws@8.21.3)(zod@4.4.3) + '@letta-ai/letta-client': 1.12.1 + '@letta-ai/trajectory': 0.2.0 + '@modelcontextprotocol/sdk': 1.30.0(zod@4.4.3) + '@pierre/diffs': 1.2.2(react-dom@19.2.8(react@18.2.0))(react@18.2.0) + '@scarf/scarf': 1.4.0 + cron-parser: 5.8.1 + cross-spawn: 7.0.6 + glob: 13.0.6 + ink-link: 5.0.0(ink@7.1.1(react@18.2.0)) + node-pty: 1.1.0 + open: 10.2.0 + react: 18.2.0 + sharp: 0.34.5 + shiki: 4.4.3 + strip-ansi: 7.2.0 + ws: 8.21.3 + optionalDependencies: + '@vscode/ripgrep': 1.18.0 + transitivePeerDependencies: + - '@cfworker/json-schema' + - bufferutil + - ink + - react-dom + - supports-color + - utf-8-validate + - zod + + '@letta-ai/trajectory@0.2.0': {} + + '@mistralai/mistralai@2.2.6(@opentelemetry/api@1.9.0)': + dependencies: + '@opentelemetry/semantic-conventions': 1.43.0 + ws: 8.21.3 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + optionalDependencies: + '@opentelemetry/api': 1.9.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@modelcontextprotocol/sdk@1.30.0(zod@4.4.3)': + dependencies: + '@hono/node-server': 2.1.0(hono@4.13.1) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + content-type: 1.0.5 + cors: 2.8.6 + cross-spawn: 7.0.6 + eventsource: 3.0.7 + eventsource-parser: 3.1.1 + express: 5.2.1 + express-rate-limit: 8.6.2(express@5.2.1) + hono: 4.13.1 + jose: 6.2.8 + json-schema-typed: 8.0.2 + pkce-challenge: 5.0.1 + raw-body: 3.0.2 + zod: 4.4.3 + zod-to-json-schema: 3.25.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + + '@opentelemetry/api@1.9.0': {} + + '@opentelemetry/semantic-conventions@1.43.0': {} + + '@pierre/diffs@1.2.2(react-dom@19.2.8(react@18.2.0))(react@18.2.0)': + dependencies: + '@pierre/theme': 1.0.3 + '@shikijs/transformers': 3.23.0 + diff: 8.0.3 + hast-util-to-html: 9.0.5 + lru_map: 0.4.1 + react: 18.2.0 + react-dom: 19.2.8(react@18.2.0) + shiki: 3.23.0 + + '@pierre/theme@1.0.3': {} + + '@protobufjs/aspromise@1.1.2': {} + + '@protobufjs/base64@1.1.2': {} + + '@protobufjs/codegen@2.0.5': {} + + '@protobufjs/eventemitter@1.1.1': {} + + '@protobufjs/fetch@1.1.1': + dependencies: + '@protobufjs/aspromise': 1.1.2 + + '@protobufjs/float@1.0.2': {} + + '@protobufjs/path@1.1.2': {} + + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.2': {} + + '@scarf/scarf@1.4.0': {} + + '@shikijs/core@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + + '@shikijs/core@4.4.3': + dependencies: + '@shikijs/primitive': 4.4.3 + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-javascript@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/engine-oniguruma@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/langs@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + + '@shikijs/primitive@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/themes@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/themes@4.4.3': + dependencies: + '@shikijs/types': 4.4.3 + + '@shikijs/transformers@3.23.0': + dependencies: + '@shikijs/core': 3.23.0 + '@shikijs/types': 3.23.0 + + '@shikijs/types@3.23.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/types@4.4.3': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@smithy/core@3.32.0': + dependencies: + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.5.0': + dependencies: + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.7.0': + dependencies: + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/node-http-handler@4.10.0': + dependencies: + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@smithy/node-http-handler@4.7.3': + dependencies: + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.7.0': + dependencies: + '@smithy/core': 3.32.0 + '@smithy/types': 4.17.0 + tslib: 2.8.1 + + '@smithy/types@4.17.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@types/hast@3.0.5': + dependencies: + '@types/unist': 3.0.3 + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/node@26.2.0': + dependencies: + undici-types: 8.3.0 + + '@types/retry@0.12.0': {} + + '@types/unist@3.0.3': {} + + '@ungap/structured-clone@1.3.3': {} + + '@vscode/ripgrep-darwin-arm64@1.18.0': + optional: true + + '@vscode/ripgrep-darwin-x64@1.18.0': + optional: true + + '@vscode/ripgrep-linux-arm64@1.18.0': + optional: true + + '@vscode/ripgrep-linux-arm@1.18.0': + optional: true + + '@vscode/ripgrep-linux-ia32@1.18.0': + optional: true + + '@vscode/ripgrep-linux-ppc64@1.18.0': + optional: true + + '@vscode/ripgrep-linux-riscv64@1.18.0': + optional: true + + '@vscode/ripgrep-linux-s390x@1.18.0': + optional: true + + '@vscode/ripgrep-linux-x64@1.18.0': + optional: true + + '@vscode/ripgrep-win32-arm64@1.18.0': + optional: true + + '@vscode/ripgrep-win32-ia32@1.18.0': + optional: true + + '@vscode/ripgrep-win32-x64@1.18.0': + optional: true + + '@vscode/ripgrep@1.18.0': + optionalDependencies: + '@vscode/ripgrep-darwin-arm64': 1.18.0 + '@vscode/ripgrep-darwin-x64': 1.18.0 + '@vscode/ripgrep-linux-arm': 1.18.0 + '@vscode/ripgrep-linux-arm64': 1.18.0 + '@vscode/ripgrep-linux-ia32': 1.18.0 + '@vscode/ripgrep-linux-ppc64': 1.18.0 + '@vscode/ripgrep-linux-riscv64': 1.18.0 + '@vscode/ripgrep-linux-s390x': 1.18.0 + '@vscode/ripgrep-linux-x64': 1.18.0 + '@vscode/ripgrep-win32-arm64': 1.18.0 + '@vscode/ripgrep-win32-ia32': 1.18.0 + '@vscode/ripgrep-win32-x64': 1.18.0 + optional: true + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + agent-base@7.1.4: {} + + ajv-formats@3.0.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 + + ajv@8.20.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.5 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + ansi-escapes@7.3.0: + dependencies: + environment: 1.1.0 + + ansi-regex@6.2.2: {} + + ansi-styles@6.2.3: {} + + auto-bind@5.0.1: {} + + balanced-match@4.0.4: {} + + base64-js@1.5.1: {} + + bignumber.js@9.3.1: {} + + body-parser@2.3.0: + dependencies: + bytes: 3.1.2 + content-type: 2.0.0 + debug: 4.4.3 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + on-finished: 2.4.1 + qs: 6.15.3 + raw-body: 3.0.2 + type-is: 2.1.0 + transitivePeerDependencies: + - supports-color + + bowser@2.14.1: {} + + brace-expansion@5.0.9: + dependencies: + balanced-match: 4.0.4 + + buffer-equal-constant-time@1.0.1: {} + + bundle-name@4.1.0: + dependencies: + run-applescript: 7.1.0 + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + ccount@2.0.1: {} + + chalk@5.6.2: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + cli-boxes@4.0.1: {} + + cli-cursor@4.0.0: + dependencies: + restore-cursor: 4.0.0 + + cli-truncate@6.1.1: + dependencies: + slice-ansi: 9.0.0 + string-width: 8.2.2 + + code-excerpt@4.0.0: + dependencies: + convert-to-spaces: 2.0.1 + + comma-separated-tokens@2.0.3: {} + + content-disposition@1.1.0: {} + + content-type@1.0.5: {} + + content-type@2.0.0: {} + + convert-to-spaces@2.0.1: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + cors@2.8.6: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cron-parser@5.8.1: + dependencies: + luxon: 3.7.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + data-uri-to-buffer@4.0.1: {} + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + default-browser-id@5.0.1: {} + + default-browser@5.5.0: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + + define-lazy-prop@3.0.0: {} + + depd@2.0.0: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@8.0.3: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ecdsa-sig-formatter@1.0.11: + dependencies: + safe-buffer: 5.2.1 + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + environment@1.1.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-toolkit@1.50.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@2.0.0: {} + + etag@1.8.1: {} + + eventsource-parser@3.1.1: {} + + eventsource@3.0.7: + dependencies: + eventsource-parser: 3.1.1 + + express-rate-limit@8.6.2(express@5.2.1): + dependencies: + debug: 4.4.3 + express: 5.2.1 + ip-address: 10.5.0 + transitivePeerDependencies: + - supports-color + + express@5.2.1: + dependencies: + accepts: 2.0.0 + body-parser: 2.3.0 + content-disposition: 1.1.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.3 + depd: 2.0.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.1 + fresh: 2.0.0 + http-errors: 2.0.1 + merge-descriptors: 2.0.0 + mime-types: 3.0.2 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.15.3 + range-parser: 1.3.0 + router: 2.2.0 + send: 1.2.1 + serve-static: 2.2.1 + statuses: 2.0.2 + type-is: 2.1.0 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-uri@3.1.5: {} + + fetch-blob@3.2.0: + dependencies: + node-domexception: 1.0.0 + web-streams-polyfill: 3.3.3 + + finalhandler@2.1.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + formdata-polyfill@4.0.10: + dependencies: + fetch-blob: 3.2.0 + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + function-bind@1.1.2: {} + + gaxios@7.3.0: + dependencies: + extend: 3.0.2 + https-proxy-agent: 7.0.6 + node-fetch: 3.3.2 + transitivePeerDependencies: + - supports-color + + gcp-metadata@8.1.2: + dependencies: + gaxios: 7.3.0 + google-logging-utils: 1.1.3 + json-bigint: 1.0.0 + transitivePeerDependencies: + - supports-color + + get-east-asian-width@1.6.0: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + glob@13.0.6: + dependencies: + minimatch: 10.2.6 + minipass: 7.1.3 + path-scurry: 2.0.2 + + google-auth-library@10.9.1: + dependencies: + base64-js: 1.5.1 + ecdsa-sig-formatter: 1.0.11 + gaxios: 7.3.0 + gcp-metadata: 8.1.2 + google-logging-utils: 1.1.3 + jws: 4.0.1 + transitivePeerDependencies: + - supports-color + + google-logging-utils@1.1.3: {} + + gopd@1.2.0: {} + + has-flag@5.0.1: {} + + has-symbols@1.1.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.5 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.5 + + hono@4.13.1: {} + + html-void-elements@3.0.0: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.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 + + iconv-lite@0.7.3: + dependencies: + safer-buffer: 2.1.2 + + indent-string@5.0.0: {} + + inherits@2.0.4: {} + + ink-link@5.0.0(ink@7.1.1(react@18.2.0)): + dependencies: + ink: 7.1.1(react@18.2.0) + terminal-link: 5.0.0 + + ink@7.1.1(react@18.2.0): + dependencies: + '@alcalzone/ansi-tokenize': 0.3.0 + ansi-escapes: 7.3.0 + ansi-styles: 6.2.3 + auto-bind: 5.0.1 + chalk: 5.6.2 + cli-boxes: 4.0.1 + cli-cursor: 4.0.0 + cli-truncate: 6.1.1 + code-excerpt: 4.0.0 + es-toolkit: 1.50.0 + indent-string: 5.0.0 + is-in-ci: 2.0.0 + patch-console: 2.0.0 + react: 18.2.0 + react-reconciler: 0.33.0(react@18.2.0) + scheduler: 0.27.0 + signal-exit: 3.0.7 + slice-ansi: 9.0.0 + stack-utils: 2.0.6 + string-width: 8.2.2 + terminal-size: 4.0.1 + type-fest: 5.8.0 + widest-line: 6.0.0 + wrap-ansi: 10.0.0 + ws: 8.21.3 + yoga-layout: 3.2.1 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + ip-address@10.5.0: {} + + ipaddr.js@1.9.1: {} + + is-docker@3.0.0: {} + + is-fullwidth-code-point@5.1.0: + dependencies: + get-east-asian-width: 1.6.0 + + is-in-ci@2.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + + is-promise@4.0.0: {} + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + + isexe@2.0.0: {} + + jose@6.2.8: {} + + js-tokens@4.0.0: {} + + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.29.7 + ts-algebra: 2.0.0 + + json-schema-traverse@1.0.0: {} + + json-schema-typed@8.0.2: {} + + jwa@2.0.1: + dependencies: + buffer-equal-constant-time: 1.0.1 + ecdsa-sig-formatter: 1.0.11 + safe-buffer: 5.2.1 + + jws@4.0.1: + dependencies: + jwa: 2.0.1 + safe-buffer: 5.2.1 + + long@5.3.2: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@11.5.2: {} + + lru_map@0.4.1: {} + + luxon@3.7.2: {} + + math-intrinsics@1.1.0: {} + + 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 + + media-typer@1.1.1: {} + + merge-descriptors@2.0.0: {} + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-encode@2.0.1: {} + + 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-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mimic-fn@2.1.0: {} + + minimatch@10.2.6: + dependencies: + brace-expansion: 5.0.9 + + minipass@7.1.3: {} + + ms@2.1.3: {} + + negotiator@1.0.0: {} + + node-addon-api@7.1.1: {} + + node-domexception@1.0.0: {} + + node-fetch@3.3.2: + dependencies: + data-uri-to-buffer: 4.0.1 + fetch-blob: 3.2.0 + formdata-polyfill: 4.0.10 + + node-pty@1.1.0: + dependencies: + node-addon-api: 7.1.1 + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + + open@10.2.0: + dependencies: + default-browser: 5.5.0 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + wsl-utils: 0.1.0 + + openai@6.26.0(ws@8.21.3)(zod@4.4.3): + optionalDependencies: + ws: 8.21.3 + zod: 4.4.3 + + p-retry@4.6.2: + dependencies: + '@types/retry': 0.12.0 + retry: 0.13.1 + + parseurl@1.3.3: {} + + partial-json@0.1.7: {} + + patch-console@2.0.0: {} + + path-key@3.1.1: {} + + path-scurry@2.0.2: + dependencies: + lru-cache: 11.5.2 + minipass: 7.1.3 + + path-to-regexp@8.4.2: {} + + pkce-challenge@5.0.1: {} + + property-information@7.2.0: {} + + protobufjs@7.6.5: + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/base64': 1.1.2 + '@protobufjs/codegen': 2.0.5 + '@protobufjs/eventemitter': 1.1.1 + '@protobufjs/fetch': 1.1.1 + '@protobufjs/float': 1.0.2 + '@protobufjs/path': 1.1.2 + '@protobufjs/pool': 1.1.0 + '@protobufjs/utf8': 1.1.2 + '@types/node': 26.2.0 + long: 5.3.2 + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + qs@6.15.3: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 + + range-parser@1.3.0: {} + + raw-body@3.0.2: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.1 + iconv-lite: 0.7.3 + unpipe: 1.0.0 + + react-dom@19.2.8(react@18.2.0): + dependencies: + react: 18.2.0 + scheduler: 0.27.0 + + react-reconciler@0.33.0(react@18.2.0): + dependencies: + react: 18.2.0 + scheduler: 0.27.0 + + react@18.2.0: + dependencies: + loose-envify: 1.4.0 + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + require-from-string@2.0.2: {} + + restore-cursor@4.0.0: + dependencies: + onetime: 5.1.2 + signal-exit: 3.0.7 + + retry@0.13.1: {} + + router@2.2.0: + dependencies: + debug: 4.4.3 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.4.2 + transitivePeerDependencies: + - supports-color + + run-applescript@7.1.0: {} + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + scheduler@0.27.0: {} + + semver@7.8.5: {} + + send@1.2.1: + dependencies: + debug: 4.4.3 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.1 + mime-types: 3.0.2 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.3.0 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.1: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.1 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shiki@3.23.0: + dependencies: + '@shikijs/core': 3.23.0 + '@shikijs/engine-javascript': 3.23.0 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + shiki@4.4.3: + dependencies: + '@shikijs/core': 4.4.3 + '@shikijs/engine-javascript': 4.4.3 + '@shikijs/engine-oniguruma': 4.4.3 + '@shikijs/langs': 4.4.3 + '@shikijs/themes': 4.4.3 + '@shikijs/types': 4.4.3 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.5 + + side-channel-list@1.0.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.1: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.1 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + signal-exit@3.0.7: {} + + slice-ansi@9.0.0: + dependencies: + ansi-styles: 6.2.3 + is-fullwidth-code-point: 5.1.0 + + space-separated-tokens@2.0.2: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + statuses@2.0.2: {} + + string-width@8.2.2: + dependencies: + get-east-asian-width: 1.6.0 + strip-ansi: 7.2.0 + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + supports-color@10.2.2: {} + + supports-hyperlinks@4.5.0: + dependencies: + has-flag: 5.0.1 + supports-color: 10.2.2 + + tagged-tag@1.0.0: {} + + terminal-link@5.0.0: + dependencies: + ansi-escapes: 7.3.0 + supports-hyperlinks: 4.5.0 + + terminal-size@4.0.1: {} + + toidentifier@1.0.1: {} + + trim-lines@3.0.1: {} + + ts-algebra@2.0.0: {} + + tslib@2.8.1: {} + + type-fest@5.8.0: + dependencies: + tagged-tag: 1.0.0 + + type-is@2.1.0: + dependencies: + content-type: 2.0.0 + media-typer: 1.1.1 + mime-types: 3.0.2 + + typebox@1.1.38: {} + + undici-types@8.3.0: {} + + 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 + + unpipe@1.0.0: {} + + vary@1.1.2: {} + + 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 + + web-streams-polyfill@3.3.3: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + widest-line@6.0.0: + dependencies: + string-width: 8.2.2 + + wrap-ansi@10.0.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 8.2.2 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + ws@8.21.3: {} + + wsl-utils@0.1.0: + dependencies: + is-wsl: 3.1.1 + + yoga-layout@3.2.1: {} + + zod-to-json-schema@3.25.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} + + zwitch@2.0.4: {} diff --git a/wiki/log/decisions/2026-08-12.md b/wiki/log/decisions/2026-08-12.md new file mode 100644 --- /dev/null +++ b/wiki/log/decisions/2026-08-12.md @@ -0,0 +1,47 @@ +# Decisions — 2026-08-12 + +``` +Type: log +``` + +## Landing observation is one exact read, not another landing path + +### DECIDED + +- One exact candidate may be classified as `ready`, `blocked`, `landed`, or + `inconsistent` by composing the repository, remote `main`, remote `pages`, public + site, project-operation state, cleanup, and explicit receipt authorities already + required by the landing workflow. The observer creates no new source of landing + truth. +- Remote refs are sampled independently and their objects are fetched only into a + disposable bare repository. The observed checkout is fingerprinted around the + read. Unknown or contradictory evidence fails closed rather than becoming absence + or a false green. +- The public edge receives one read. A remote `pages` snapshot carrying the exact + source can prove publication while an older public edge is still converging; that + ordinary lag is named but not polled. +- Optional interpretation is subordinate to deterministic classification. Exactly + one retained agent named `Misaligned Landing Observer` is reused; absence + provisions it, while duplicate exact names fail closed. It has empty memory, MemFS + disabled, and no tools or skills. Every observation opens a fresh stateless + conversation over minimized evidence, and its answer cannot change the receipt. +- Receipt production and `tools/task.sh` integration remain outside this slice. The + observer accepts optional exact receipts without inventing or backfilling them. + +### REJECTED + +- **Let the specialist decide whether the landing succeeded.** Interpretation is + useful around anomalies, but an LLM judgment is not an execution receipt. +- **Create and delete a worker for every observation.** One retained agent preserves + a stable identity without carrying receipt history because every conversation is + fresh and stateless. +- **Reuse the specialist's default conversation.** Prior evidence must not leak into + the next exact read. +- **Fetch into, repair, deploy, notify from, schedule through, or clean the observed + repository.** Observation has no mutation doorway. +- **Poll until the public edge agrees.** Remote publication and edge convergence are + separate facts; one read is enough unless a real deployment failure is being + diagnosed. + +Owners: [repository skills](../../process/repository-skills.md) and +[landing workflow](../../process/workflows.md#git-conventions). diff --git a/.agents/skills/observing-misaligned-landings/scripts/interpret-anomalies.mjs b/.agents/skills/observing-misaligned-landings/scripts/interpret-anomalies.mjs new file mode 100644 --- /dev/null +++ b/.agents/skills/observing-misaligned-landings/scripts/interpret-anomalies.mjs @@ -0,0 +1,312 @@ +#!/usr/bin/env node + +import { readFile } from "node:fs/promises"; +import { stdin } from "node:process"; +import { pathToFileURL } from "node:url"; + +export const RECEIPT_SCHEMA = "network.comind.misaligned.landing-observation/v2"; +export const INTERPRETATION_SCHEMA = + "network.comind.misaligned.landing-interpretation/v1"; +export const MODEL = "letta/auto"; +export const SPECIALIST_NAME = "Misaligned Landing Observer"; +const MAX_RECEIPT_BYTES = 256 * 1024; +const BENIGN_ANOMALY_CODES = new Set(["public_edge_converging"]); +const INTERPRETER_SYSTEM_PROMPT = [ + "You are the retained Misaligned Landing Observer interpreting exactly one minimized deterministic landing receipt in a fresh stateless conversation.", + "You have no tools, skills, repository access, or authority to mutate anything.", + "The supplied classifier state is authoritative and immutable; explain anomalies without changing that state, acting, or promising action.", +].join(" "); + +function validateFacts(value, field) { + if (!Array.isArray(value)) { + throw new Error(`landing receipt must carry a ${field} array`); + } + for (const row of value) { + if ( + !row || + typeof row !== "object" || + Array.isArray(row) || + typeof row.code !== "string" || + row.code.length === 0 || + typeof row.summary !== "string" || + row.summary.length === 0 + ) { + throw new Error(`landing receipt ${field} entries must carry code and summary strings`); + } + } +} + +export function validateReceipt(value) { + if (!value || typeof value !== "object" || Array.isArray(value)) { + throw new Error("landing receipt must be a JSON object"); + } + if (value.schema !== RECEIPT_SCHEMA) { + throw new Error(`unsupported landing receipt schema: ${String(value.schema)}`); + } + const states = new Set(["ready", "blocked", "landed", "inconsistent"]); + if (!states.has(value.state)) { + throw new Error( + "landing receipt state must be ready, blocked, landed, or inconsistent", + ); + } + validateFacts(value.missing_steps, "missing_steps"); + validateFacts(value.ownership_warnings, "ownership_warnings"); + validateFacts(value.anomalies, "anomalies"); + if (value.state === "inconsistent" && value.anomalies.length === 0) { + throw new Error("an inconsistent landing receipt must name at least one anomaly"); + } + if ( + value.state !== "inconsistent" && + value.state !== "landed" && + value.anomalies.length !== 0 + ) { + throw new Error("only inconsistent or landed receipts may carry anomalies"); + } + if (!value.evidence || typeof value.evidence !== "object" || Array.isArray(value.evidence)) { + throw new Error("landing receipt evidence must be a JSON object"); + } + return value; +} + +export function needsInterpretation(receipt) { + return validateReceipt(receipt).anomalies.some( + (row) => !BENIGN_ANOMALY_CODES.has(row.code), + ); +} + +function pick(source, keys) { + if (!source || typeof source !== "object" || Array.isArray(source)) { + return {}; + } + return Object.fromEntries( + keys.filter((key) => Object.hasOwn(source, key)).map((key) => [key, source[key]]), + ); +} + +function safeFacts(rows, { summaries = true } = {}) { + return rows.map((row) => (summaries ? { code: row.code, summary: row.summary } : { code: row.code })); +} + +/** Minimize evidence before it crosses the repository boundary. */ +export function interpretationReceipt(receipt) { + const value = validateReceipt(receipt); + const evidence = value.evidence; + const project = pick(evidence.project_status, [ + "consistent", + "error_count", + "generated_ledgers_fresh", + "generated_work_orders_fresh", + "readable", + "target_run_ambiguous", + "target_worktree_ambiguous", + "warning_count", + ]); + project.target_run = pick(evidence.project_status?.target_run, [ + "phase", + "present", + "status", + ]); + const target = pick(evidence.target_worktree, [ + "ahead", + "behind", + "dirty", + "head_revision", + "present", + ]); + target.path_escape_detected = Boolean(evidence.target_worktree?.path_escape); + + const receipts = {}; + for (const kind of ["gate", "deployment", "channel"]) { + receipts[kind] = pick(evidence.receipts?.[kind], [ + "channel", + "pages_revision", + "provided", + "revision", + "source_revision", + "status", + "valid", + ]); + } + + return { + anomalies: safeFacts(value.anomalies), + evidence: { + pages: pick(evidence.pages, [ + "available", + "snapshot_matches_ref", + "snapshot_revision", + "source_is_expected", + "source_revision", + "title_contract", + ]), + primary_worktree: pick(evidence.primary_worktree, ["dirty", "present"]), + project_status: project, + public_site: pick(evidence.public_site, [ + "attempted", + "contract_ok", + "source_is_expected", + "source_revision", + ]), + receipts, + repository: pick(evidence.repository, [ + "candidate_head_stable", + "hinted_root_matches", + "local_main_revision", + "readable", + "remote_main_contains_expected", + "remote_main_is_expected", + "remote_main_revision", + "remote_pages_revision", + "remote_refs_readable", + "remote_refs_stable", + "snapshot_main_matches_ref", + "snapshot_main_revision", + ]), + target_worktree: target, + }, + exact_revision: value.exact_revision ?? null, + missing_steps: safeFacts(value.missing_steps), + ownership_warnings: safeFacts(value.ownership_warnings, { summaries: false }), + plain_summary: + typeof value.plain_summary === "string" ? value.plain_summary : null, + schema: value.schema, + state: value.state, + }; +} + +export function buildPrompt(receipt) { + const projected = interpretationReceipt(receipt); + return [ + "A strictly read-only Misaligned landing observer found deterministic anomalies.", + `The deterministic state is ${projected.state}; you may explain it but must not change it.`, + "Interpret only the supplied evidence. Do not use tools, request repository access, mutate state, promise future work, or treat your judgment as replacing the classifier.", + "Omitted, null, or empty evidence is unknown, never proof that a step is intact. Do not invent a revision, placeholder meaning, classifier state, or absent fact.", + "Separate likely transient publication convergence from a broken landing, stale evidence, task-ownership ambiguity, or project-operation inconsistency.", + "Return: (1) the smallest plain-language diagnosis, (2) which exact supplied evidence supports it, and (3) at most one read-only next verification if the supplied evidence cannot decide the diagnosis. Do not recommend polling.", + "", + "MINIMIZED LANDING RECEIPT", + JSON.stringify(projected, null, 2), + ].join("\n"); +} + +async function readReceipt(path) { + const chunks = []; + if (!path || path === "-") { + for await (const chunk of stdin) { + chunks.push(Buffer.from(chunk)); + } + } + const input = path && path !== "-" ? await readFile(path) : Buffer.concat(chunks); + if (input.byteLength > MAX_RECEIPT_BYTES) { + throw new Error(`landing receipt exceeds ${MAX_RECEIPT_BYTES} bytes`); + } + return validateReceipt(JSON.parse(input.toString("utf8"))); +} + +function agentId(agent) { + return agent && typeof agent.id === "string" && agent.id.length > 0 + ? agent.id + : null; +} + +export async function findOrCreateSpecialist(client) { + const listed = await client.agents.list({ name: SPECIALIST_NAME, limit: 100 }); + if (!Array.isArray(listed)) { + throw new Error("Letta agent lookup returned an unsupported result"); + } + const exact = listed.filter((agent) => agent?.name === SPECIALIST_NAME); + if (exact.length > 1) { + throw new Error(`more than one Letta agent is named ${SPECIALIST_NAME}`); + } + if (exact.length === 1) { + const existingId = agentId(exact[0]); + if (!existingId) { + throw new Error("the retained landing observer has no usable agent id"); + } + return { agentId: existingId, created: false }; + } + const createdId = await client.createAgent({ + baseTools: [], + description: + "Retained zero-tool specialist for interpreting deterministic Misaligned landing anomalies", + memfs: false, + memory: [], + model: MODEL, + name: SPECIALIST_NAME, + systemPrompt: INTERPRETER_SYSTEM_PROMPT, + }); + if (typeof createdId !== "string" || createdId.length === 0) { + throw new Error("creating the retained landing observer returned no usable agent id"); + } + return { agentId: createdId, created: true }; +} + +export async function interpret( + receipt, + env = process.env, + sdkLoader = () => import("@letta-ai/letta-agent-sdk"), +) { + const validated = validateReceipt(receipt); + if (!needsInterpretation(validated)) { + return { + interpretation: null, + model: MODEL, + reason: + validated.anomalies.length === 0 + ? "deterministic receipt has no anomalies" + : "deterministic receipt has only benign public-edge convergence", + schema: INTERPRETATION_SCHEMA, + status: "not-needed", + }; + } + const { LettaAgentClient } = await sdkLoader(); + const clientOptions = { + backend: "cloud", + ...(env.LETTA_API_KEY ? { apiKey: env.LETTA_API_KEY } : {}), + ...(env.LETTA_BASE_URL ? { apiBaseUrl: env.LETTA_BASE_URL } : {}), + }; + const client = new LettaAgentClient(clientOptions); + const specialist = await findOrCreateSpecialist(client); + const result = await client.prompt(buildPrompt(validated), specialist.agentId, { + allowedTools: [], + permissionMode: "strict", + skillSources: [], + stateless: true, + tools: [], + toolset: { base: "none" }, + }); + return { + agent_created: specialist.created, + agent_id: specialist.agentId, + agent_name: SPECIALIST_NAME, + conversation_id: result.conversationId, + interpretation: result.result ?? result.errorDetail ?? result.error ?? null, + model: MODEL, + schema: INTERPRETATION_SCHEMA, + status: result.success ? "ok" : "failed", + stop_reason: result.stopReason ?? null, + }; +} + +async function main(argv = process.argv.slice(2)) { + if (argv.length > 1 || argv[0] === "--help" || argv[0] === "-h") { + const stream = argv[0] === "--help" || argv[0] === "-h" ? process.stdout : process.stderr; + stream.write("usage: interpret-anomalies.mjs [receipt.json|-]\n"); + return argv.length > 1 ? 2 : 0; + } + try { + const receipt = await readReceipt(argv[0] ?? "-"); + const result = await interpret(receipt); + process.stdout.write(`${JSON.stringify(result, null, 2)}\n`); + return result.status === "failed" ? 1 : 0; + } catch (error) { + process.stderr.write( + `landing interpretation: ${error instanceof Error ? error.message : String(error)}\n`, + ); + return 2; + } +} + +if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) { + process.exitCode = await main(); +} diff --git a/.agents/skills/observing-misaligned-landings/scripts/observe-landing.py b/.agents/skills/observing-misaligned-landings/scripts/observe-landing.py new file mode 100644 --- /dev/null +++ b/.agents/skills/observing-misaligned-landings/scripts/observe-landing.py @@ -0,0 +1,1282 @@ +#!/usr/bin/env python3 +"""Emit one deterministic, strictly read-only Misaligned landing observation.""" + +from __future__ import annotations + +import argparse +from dataclasses import dataclass +from html.parser import HTMLParser +import json +import os +from pathlib import Path +import re +import subprocess +import sys +import tempfile +from typing import Callable +from urllib.parse import urlsplit, urlunsplit + + +SCHEMA = "network.comind.misaligned.landing-observation/v2" +GATE_SCHEMA = "network.comind.misaligned.landing-gate-receipt/v1" +DEPLOYMENT_SCHEMA = "network.comind.misaligned.deployment-receipt/v1" +CHANNEL_SCHEMA = "network.comind.misaligned.channel-delivery-receipt/v1" +TITLE = "Misaligned — WORK / THINK / LIE" +DEFAULT_SITE_URL = "https://cameron.tngl.io/misaligned/" +SHA_RE = re.compile(r"^[0-9a-f]{40}$") +SOURCE_OUTPUT_RE = re.compile(r"(?:source=)([0-9a-f]{40}|missing)") + + +@dataclass(frozen=True) +class CommandResult: + returncode: int + stdout: str = "" + stderr: str = "" + + +Runner = Callable[..., CommandResult] + + +class PageContractParser(HTMLParser): + def __init__(self) -> None: + super().__init__() + self.source_revision: str | None = None + self._in_title = False + self._title_parts: list[str] = [] + + @property + def title(self) -> str: + return "".join(self._title_parts).strip() + + def handle_starttag(self, tag: str, attrs: list[tuple[str, str | None]]) -> None: + if tag.lower() == "title": + self._in_title = True + if tag.lower() != "meta": + return + values = {key.lower(): value for key, value in attrs} + if values.get("name") == "misaligned-source-revision": + self.source_revision = values.get("content") + + def handle_endtag(self, tag: str) -> None: + if tag.lower() == "title": + self._in_title = False + + def handle_data(self, data: str) -> None: + if self._in_title: + self._title_parts.append(data) + + +def read_only_env(extra: dict[str, str] | None = None) -> dict[str, str]: + environment = os.environ.copy() + environment["GIT_OPTIONAL_LOCKS"] = "0" + if extra: + environment.update(extra) + return environment + + +def command_runner( + command: list[str], + *, + cwd: Path, + env: dict[str, str] | None = None, + timeout: int = 45, +) -> CommandResult: + try: + completed = subprocess.run( + command, + cwd=cwd, + env=env or read_only_env(), + text=True, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + timeout=timeout, + check=False, + ) + return CommandResult(completed.returncode, completed.stdout, completed.stderr) + except (OSError, subprocess.TimeoutExpired) as exc: + return CommandResult(127, "", str(exc)) + + +def redact_url(value: str) -> str: + try: + parsed = urlsplit(value) + except ValueError: + return value + if parsed.scheme not in {"http", "https", "ssh"}: + return value + host = parsed.hostname or "" + if parsed.port: + host = f"{host}:{parsed.port}" + return urlunsplit((parsed.scheme, host, parsed.path, "" if parsed.query else "", "")) + + +def clean_line(result: CommandResult) -> str: + lines = (result.stderr or result.stdout).strip().splitlines() + if not lines: + return f"command exited {result.returncode}" + line = lines[-1] + line = re.sub(r"(https?://)[^/@\s]+@", r"\1@", line) + line = re.sub(r"(?i)(token|api[_-]?key|password)=([^\s&]+)", r"\1=", line) + for candidate in re.findall(r"(?:https?|ssh)://[^\s]+", line): + line = line.replace(candidate, redact_url(candidate)) + return line[:240] + + +def git(runner: Runner, root: Path, *args: str, **kwargs: object) -> CommandResult: + kwargs.setdefault("env", read_only_env()) + return runner(["git", "-C", str(root), *args], cwd=root, **kwargs) + + +def one_sha(result: CommandResult) -> str | None: + value = result.stdout.strip() + return value if result.returncode == 0 and SHA_RE.fullmatch(value) else None + + +def bool_or_none(value: object) -> bool | None: + return value if isinstance(value, bool) else None + + +def remote_refs(result: CommandResult) -> dict[str, str]: + refs: dict[str, str] = {} + if result.returncode != 0: + return refs + for line in result.stdout.splitlines(): + sha, separator, ref = line.partition("\t") + if separator and SHA_RE.fullmatch(sha): + refs[ref] = sha + return refs + + +def page_contract(html: str) -> tuple[str | None, bool]: + parser = PageContractParser() + parser.feed(html) + source = parser.source_revision + if source is not None and not SHA_RE.fullmatch(source): + source = None + return source, parser.title == TITLE + + +def public_source(output: str) -> str | None: + for value in reversed(SOURCE_OUTPUT_RE.findall(output)): + if SHA_RE.fullmatch(value): + return value + return None + + +def list_output(result: CommandResult) -> list[str]: + if result.returncode != 0: + return [] + return sorted(line for line in result.stdout.splitlines() if line) + + +def count_pair(result: CommandResult) -> tuple[int | None, int | None]: + if result.returncode != 0: + return None, None + parts = result.stdout.split() + if len(parts) != 2 or not all(part.isdigit() for part in parts): + return None, None + return int(parts[0]), int(parts[1]) + + +def primary_root(runner: Runner, root: Path) -> Path | None: + result = git( + runner, + root, + "rev-parse", + "--path-format=absolute", + "--git-common-dir", + ) + if result.returncode != 0: + return None + common = Path(result.stdout.strip()) + if common.name == ".git": + return common.parent + marker = "/.git/worktrees/" + raw = str(common) + if marker in raw: + return Path(raw.split(marker, 1)[0]) + return None + + +def live_worktree(runner: Runner, path: Path | None) -> dict[str, object]: + evidence: dict[str, object] = { + "ahead": None, + "behind": None, + "branch": None, + "dirty": None, + "head_revision": None, + "path": str(path) if path is not None else None, + "path_escape": None, + "present": None if path is None else False, + "touching": [], + "upstream": None, + } + if path is None: + return evidence + root_result = git(runner, path, "rev-parse", "--show-toplevel") + if root_result.returncode != 0: + return evidence + canonical = Path(root_result.stdout.strip()) + requested = path.resolve() + if canonical.resolve() != requested: + evidence["path_escape"] = str(canonical) + return evidence + evidence["path"] = str(canonical) + evidence["present"] = True + evidence["head_revision"] = one_sha( + git(runner, canonical, "rev-parse", "--verify", "HEAD^{commit}") + ) + branch = git(runner, canonical, "branch", "--show-current") + evidence["branch"] = branch.stdout.strip() if branch.returncode == 0 else None + status = git(runner, canonical, "status", "--porcelain", "--untracked-files=normal") + evidence["dirty"] = bool(status.stdout) if status.returncode == 0 else None + upstream = git(runner, canonical, "rev-parse", "--abbrev-ref", "@{upstream}") + evidence["upstream"] = upstream.stdout.strip() if upstream.returncode == 0 else None + return evidence + + +def path_matches_task(row: dict[str, object], task: str) -> bool: + raw_path = row.get("path") + branch = str(row.get("branch", "")) + path_name = Path(raw_path).name if isinstance(raw_path, str) and raw_path else "" + tail = branch.rsplit("/", 1)[-1] + return ( + path_name == task + or branch == f"worktree-{task}" + or tail == task + or tail.startswith(f"{task}-") + ) + + +def normalize_run(row: dict[str, object]) -> dict[str, object]: + return { + "agent_id": row.get("agent_id") if isinstance(row.get("agent_id"), str) else None, + "phase": row.get("phase") if isinstance(row.get("phase"), str) else None, + "present": True, + "status": row.get("status") if isinstance(row.get("status"), str) else None, + "worktree": row.get("worktree") if isinstance(row.get("worktree"), str) else None, + } + + +def project_observation( + runner: Runner, + root: Path, + task: str, + primary: Path | None, +) -> tuple[dict[str, object], Path | None]: + project_script = root / "tools/project-status.py" + result = runner( + [ + sys.executable, + str(project_script), + "--root", + str(root), + "--json", + "--check", + "--offline", + ], + cwd=root, + env=read_only_env(), + timeout=45, + ) + evidence: dict[str, object] = { + "consistent": None, + "error_count": None, + "generated_ledgers_fresh": None, + "generated_work_orders_fresh": None, + "read_error": None, + "readable": False, + "target_run": { + "agent_id": None, + "phase": None, + "present": None, + "status": None, + "worktree": None, + }, + "target_run_ambiguous": None, + "target_worktree_ambiguous": None, + "warning_count": None, + } + try: + payload = json.loads(result.stdout) + except json.JSONDecodeError: + payload = None + if not isinstance(payload, dict): + evidence["read_error"] = clean_line(result) + return evidence, None + + consistency = payload.get("consistency") + freshness = payload.get("freshness") + runs = payload.get("runs") + worktrees = payload.get("worktrees") + if not ( + isinstance(consistency, dict) + and isinstance(freshness, dict) + and isinstance(runs, list) + and isinstance(worktrees, list) + and isinstance(consistency.get("ok"), bool) + ): + evidence["read_error"] = "project-status returned an unsupported JSON shape" + return evidence, None + + evidence["readable"] = True + evidence["consistent"] = consistency["ok"] + errors = consistency.get("errors") if isinstance(consistency.get("errors"), list) else [] + warnings = consistency.get("warnings") if isinstance(consistency.get("warnings"), list) else [] + evidence["error_count"] = len(errors) + evidence["warning_count"] = len(warnings) + evidence["generated_ledgers_fresh"] = bool_or_none(freshness.get("ledgers")) + evidence["generated_work_orders_fresh"] = bool_or_none(freshness.get("work_orders")) + + matching_runs = [row for row in runs if isinstance(row, dict) and row.get("id") == task] + evidence["target_run_ambiguous"] = len(matching_runs) > 1 + target_run = matching_runs[0] if len(matching_runs) == 1 else None + if target_run is not None: + evidence["target_run"] = normalize_run(target_run) + else: + evidence["target_run"]["present"] = False if len(matching_runs) == 0 else None + + registered = [row for row in worktrees if isinstance(row, dict) and "error" not in row] + explicit = target_run.get("worktree") if isinstance(target_run, dict) else None + candidates: list[dict[str, object]] = [] + for row in registered: + raw_path = row.get("path") + if not isinstance(raw_path, str) or not raw_path: + continue + if ( + isinstance(explicit, str) + and explicit + and Path(raw_path).resolve() == Path(explicit).resolve() + ) or path_matches_task(row, task): + if row not in candidates: + candidates.append(row) + evidence["target_worktree_ambiguous"] = len(candidates) > 1 + target_path = None + if len(candidates) == 1 and isinstance(candidates[0].get("path"), str): + target_path = Path(str(candidates[0]["path"])) + elif ( + len(candidates) == 0 + and isinstance(explicit, str) + and explicit + ): + # A completed run retains the exact path after normal cleanup. Reading + # that absent path is the cleanup proof; do not guess a worktree root. + target_path = Path(explicit) + return evidence, target_path + + +def isolated_remote_snapshot( + runner: Runner, + root: Path, + remote_url: str, + ssh_command: str | None, + expected: str | None, + sampled_main: str | None, + sampled_pages: str | None, +) -> dict[str, object]: + """Read remote history and page bytes in a disposable bare repository.""" + snapshot: dict[str, object] = { + "changed_paths": None, + "main_contains_expected": None, + "main_read_error": None, + "main_revision": None, + "page_read_error": None, + "page_revision": None, + "page_source_revision": None, + "page_title_contract": None, + "target_ahead": None, + "target_behind": None, + } + with tempfile.TemporaryDirectory(prefix="misaligned-landing-observer-") as raw_tmp: + tmp = Path(raw_tmp) + initialized = runner( + ["git", "init", "--bare", "-q", str(tmp)], + cwd=root, + env=read_only_env(), + ) + if initialized.returncode != 0: + message = clean_line(initialized) + snapshot["main_read_error"] = message + snapshot["page_read_error"] = message + return snapshot + + fetch_env = read_only_env() + if ssh_command: + fetch_env["GIT_SSH_COMMAND"] = ssh_command + + if sampled_main is not None: + fetched_main = runner( + [ + "git", + "-C", + str(tmp), + "fetch", + "--quiet", + "--no-tags", + remote_url, + "+refs/heads/main:refs/observer/main", + ], + cwd=root, + env=fetch_env, + timeout=60, + ) + if fetched_main.returncode != 0: + snapshot["main_read_error"] = clean_line(fetched_main) + else: + snapshot["main_revision"] = one_sha( + git(runner, tmp, "rev-parse", "--verify", "refs/observer/main^{commit}") + ) + if snapshot["main_revision"] != sampled_main: + snapshot["main_read_error"] = ( + "disposable main snapshot does not match the sampled remote ref" + ) + + if sampled_pages is not None: + fetched_pages = runner( + [ + "git", + "-C", + str(tmp), + "fetch", + "--quiet", + "--no-tags", + "--depth=1", + remote_url, + "+refs/heads/pages:refs/observer/pages", + ], + cwd=root, + env=fetch_env, + timeout=60, + ) + if fetched_pages.returncode != 0: + snapshot["page_read_error"] = clean_line(fetched_pages) + else: + page_revision = one_sha( + git(runner, tmp, "rev-parse", "--verify", "refs/observer/pages^{commit}") + ) + snapshot["page_revision"] = page_revision + if page_revision != sampled_pages: + snapshot["page_read_error"] = ( + "disposable pages snapshot does not match the sampled remote ref" + ) + return snapshot + shown = git(runner, tmp, "show", "refs/observer/pages:index.html") + if page_revision is None or shown.returncode != 0: + snapshot["page_read_error"] = clean_line(shown) + else: + source, title_ok = page_contract(shown.stdout) + snapshot["page_source_revision"] = source + snapshot["page_title_contract"] = title_ok + + main_revision = snapshot["main_revision"] + if expected is None or not isinstance(main_revision, str): + return snapshot + + candidate_ref = "refs/observer/main" + if expected != main_revision: + candidate_ref = "refs/observer/candidate" + fetched_candidate = runner( + [ + "git", + "-C", + str(tmp), + "fetch", + "--quiet", + "--no-tags", + str(root), + f"+{expected}:{candidate_ref}", + ], + cwd=root, + env=read_only_env(), + timeout=60, + ) + if fetched_candidate.returncode != 0: + snapshot["main_read_error"] = clean_line(fetched_candidate) + return snapshot + candidate_revision = one_sha( + git(runner, tmp, "rev-parse", "--verify", f"{candidate_ref}^{{commit}}") + ) + if candidate_revision != expected: + snapshot["main_read_error"] = "disposable candidate snapshot did not resolve the expected revision" + return snapshot + + if expected == main_revision: + snapshot["main_contains_expected"] = True + else: + ancestry = git( + runner, + tmp, + "merge-base", + "--is-ancestor", + candidate_ref, + "refs/observer/main", + ) + snapshot["main_contains_expected"] = ( + True if ancestry.returncode == 0 else False if ancestry.returncode == 1 else None + ) + if ancestry.returncode not in {0, 1}: + snapshot["main_read_error"] = clean_line(ancestry) + return snapshot + + counts = git( + runner, + tmp, + "rev-list", + "--left-right", + "--count", + f"refs/observer/main...{candidate_ref}", + ) + behind, ahead = count_pair(counts) + snapshot["target_behind"] = behind + snapshot["target_ahead"] = ahead + if behind is None or ahead is None: + snapshot["main_read_error"] = clean_line(counts) + return snapshot + changed = git( + runner, + tmp, + "diff", + "--name-only", + f"refs/observer/main...{candidate_ref}", + ) + snapshot["changed_paths"] = ( + list_output(changed) if changed.returncode == 0 else None + ) + return snapshot + + +def read_receipt(path: Path | None, kind: str) -> dict[str, object]: + schema = { + "gate": GATE_SCHEMA, + "deployment": DEPLOYMENT_SCHEMA, + "channel": CHANNEL_SCHEMA, + }[kind] + normalized: dict[str, object] = { + "provided": path is not None, + "read_error": None, + "valid": None, + } + if path is None: + return normalized + try: + payload = json.loads(path.read_text(encoding="utf-8")) + except (OSError, json.JSONDecodeError) as exc: + normalized.update(valid=False, read_error=f"{kind} receipt unreadable: {exc}") + return normalized + if not isinstance(payload, dict) or payload.get("schema") != schema: + normalized.update(valid=False, read_error=f"{kind} receipt has an unsupported schema") + return normalized + + if kind == "gate": + status = payload.get("status") + revision = payload.get("revision") + valid = status in {"pass", "fail"} and isinstance(revision, str) and bool( + SHA_RE.fullmatch(revision) + ) + normalized.update(status=status, revision=revision, valid=valid) + elif kind == "deployment": + status = payload.get("status") + source = payload.get("source_revision") + pages = payload.get("pages_revision") + valid = ( + status in {"pass", "fail"} + and isinstance(source, str) + and bool(SHA_RE.fullmatch(source)) + and (pages is None or (isinstance(pages, str) and bool(SHA_RE.fullmatch(pages)))) + ) + normalized.update( + status=status, + source_revision=source, + pages_revision=pages, + valid=valid, + ) + else: + status = payload.get("status") + channel = payload.get("channel") + revision = payload.get("revision") + raw_message_id = payload.get("message_id") + message_id = str(raw_message_id) if isinstance(raw_message_id, (str, int)) else None + revision_valid = isinstance(revision, str) and bool(SHA_RE.fullmatch(revision)) + message_valid = ( + status != "delivered" + or (isinstance(message_id, str) and message_id.isdigit()) + ) + valid = ( + channel == "telegram" + and status in {"delivered", "unavailable", "failed", "unknown"} + and revision_valid + and message_valid + ) + normalized.update( + channel=channel, + message_id=message_id, + revision=revision if isinstance(revision, str) else None, + status=status, + valid=valid, + ) + if normalized["valid"] is False and normalized["read_error"] is None: + normalized["read_error"] = f"{kind} receipt has invalid fields" + return normalized + + +def fact(code: str, summary: str) -> dict[str, str]: + return {"code": code, "summary": summary} + + +def append_once(rows: list[dict[str, str]], code: str, summary: str) -> None: + if not any(row["code"] == code for row in rows): + rows.append(fact(code, summary)) + + +def classify( + evidence: dict[str, object], + exact_revision: str | None, +) -> tuple[str, list[dict[str, str]], list[dict[str, str]], list[dict[str, str]], str]: + """Classify one immutable evidence manifest without I/O or agent judgment.""" + missing: list[dict[str, str]] = [] + ownership: list[dict[str, str]] = [] + anomalies: list[dict[str, str]] = [] + + repository = evidence.get("repository") if isinstance(evidence.get("repository"), dict) else {} + pages = evidence.get("pages") if isinstance(evidence.get("pages"), dict) else {} + public = evidence.get("public_site") if isinstance(evidence.get("public_site"), dict) else {} + project = evidence.get("project_status") if isinstance(evidence.get("project_status"), dict) else {} + receipts = evidence.get("receipts") if isinstance(evidence.get("receipts"), dict) else {} + gate = receipts.get("gate") if isinstance(receipts.get("gate"), dict) else {} + deployment = receipts.get("deployment") if isinstance(receipts.get("deployment"), dict) else {} + channel = receipts.get("channel") if isinstance(receipts.get("channel"), dict) else {} + target_run = project.get("target_run") if isinstance(project.get("target_run"), dict) else {} + target = evidence.get("target_worktree") if isinstance(evidence.get("target_worktree"), dict) else {} + primary = evidence.get("primary_worktree") if isinstance(evidence.get("primary_worktree"), dict) else {} + + def conflict(code: str, summary: str) -> None: + append_once(anomalies, code, summary) + + if repository.get("readable") is not True: + conflict("repository_unreadable", "the supplied path is not a readable Git worktree") + elif repository.get("hinted_root_matches") is not True: + conflict("repository_path_escaped", "the supplied root resolves to a different enclosing Git worktree") + if exact_revision is None: + conflict("expected_revision_unresolved", "the expected candidate does not resolve to one commit") + if repository.get("remote_refs_readable") is not True: + conflict("remote_refs_unreadable", "the remote main/pages refs could not be read authoritatively") + elif repository.get("remote_refs_stable") is not True: + conflict("remote_refs_moved_during_observation", "main or pages moved during the one-shot observation") + elif repository.get("remote_main_revision") is None: + conflict("remote_main_absent", "the authoritative remote has no main branch") + elif repository.get("snapshot_main_matches_ref") is not True: + code = ( + "remote_main_snapshot_mismatched_ref" + if repository.get("snapshot_main_revision") is not None + else "remote_main_snapshot_unreadable" + ) + conflict(code, "the disposable remote-main snapshot could not prove the sampled main ref") + elif ( + exact_revision is not None + and repository.get("remote_main_is_expected") is False + and not isinstance(repository.get("remote_main_contains_expected"), bool) + ): + conflict("remote_ancestry_unreadable", "the disposable snapshot could not determine whether remote main contains the candidate") + if repository.get("candidate_head_stable") is None: + conflict("candidate_head_unreadable", "the observed candidate HEAD could not be read twice") + elif repository.get("candidate_head_stable") is False: + conflict("candidate_moved_during_observation", "the target worktree HEAD changed during observation") + if project.get("readable") is not True: + conflict("project_status_unreadable", "project-status did not return supported JSON") + elif project.get("consistent") is not True: + conflict("project_status_inconsistent", "project-operation records contradict each other") + if project.get("target_run_ambiguous") is True: + conflict("target_run_ambiguous", "more than one run record claims the target task id") + if project.get("target_worktree_ambiguous") is True: + conflict("target_worktree_ambiguous", "more than one registered worktree matches the target task") + if pages.get("available") is None and repository.get("remote_pages_revision") is not None: + conflict("pages_authority_unreadable", "the remote pages branch exists but its isolated snapshot could not be read") + if pages.get("snapshot_revision") is not None and pages.get("snapshot_matches_ref") is not True: + conflict("pages_snapshot_mismatched_ref", "the isolated pages snapshot does not match the sampled pages ref") + + for kind, receipt in (("gate", gate), ("deployment", deployment), ("channel", channel)): + if receipt.get("provided") is True and receipt.get("valid") is not True: + conflict(f"{kind}_receipt_invalid", f"the supplied {kind} receipt is malformed or unreadable") + + if exact_revision is not None and gate.get("valid") is True: + if gate.get("revision") != exact_revision: + conflict("gate_revision_mismatch", "the gate receipt belongs to a different revision") + elif gate.get("status") == "fail" and repository.get("remote_main_contains_expected") is True: + conflict("landed_without_passing_gate_receipt", "remote state contains a revision whose supplied gate receipt failed") + if exact_revision is not None and deployment.get("valid") is True: + if deployment.get("source_revision") != exact_revision: + conflict("deployment_revision_mismatch", "the deployment receipt belongs to a different source revision") + receipt_pages = deployment.get("pages_revision") + if isinstance(receipt_pages, str) and receipt_pages != repository.get("remote_pages_revision"): + conflict("deployment_pages_revision_mismatch", "the deployment receipt names a different remote pages revision") + if ( + deployment.get("status") == "pass" + and repository.get("remote_main_is_expected") is True + and pages.get("source_is_expected") is False + ): + conflict("deployment_receipt_conflicts_with_pages", "a passing deployment receipt conflicts with remote pages") + if exact_revision is not None and channel.get("valid") is True: + if channel.get("revision") != exact_revision: + conflict("channel_revision_mismatch", "the Telegram delivery receipt belongs to a different revision") + + remote_contains = repository.get("remote_main_contains_expected") + page_exact = pages.get("source_is_expected") is True + if page_exact and remote_contains is False: + conflict("published_revision_not_on_main", "remote pages names a revision absent from remote main") + run_status = target_run.get("status") + if run_status == "ok" and remote_contains is False: + conflict("terminal_run_without_remote_landing", "the task run is complete but remote main does not contain the candidate") + if run_status == "fail" and remote_contains is True: + conflict("failed_run_contains_remote_landing", "the task run failed even though remote main contains the candidate") + if target.get("path_escape") is not None: + conflict( + "target_path_escaped", + "the recorded target path resolves to a different enclosing Git worktree", + ) + + if anomalies: + short = exact_revision[:12] if exact_revision else "the requested candidate" + return ( + "inconsistent", + missing, + ownership, + anomalies, + f"Evidence conflicts for {short}; no landing conclusion is safe.", + ) + + caller = evidence.get("input") if isinstance(evidence.get("input"), dict) else {} + caller_agent = caller.get("agent_id") + owner = target_run.get("agent_id") + owner_matches = ( + isinstance(caller_agent, str) + and bool(caller_agent) + and isinstance(owner, str) + and bool(owner) + and caller_agent == owner + ) + if isinstance(caller_agent, str) and caller_agent and isinstance(owner, str) and owner and not owner_matches: + append_once(ownership, "foreign_task_owner", f"the target run belongs to {owner}, not {caller_agent}") + elif not owner_matches: + append_once(ownership, "task_ownership_unproven", "the current agent cannot be matched to the target run owner") + + cleanup_complete = run_status == "ok" and target.get("present") is False + exact_remote = repository.get("remote_main_is_expected") is True + current_pages = ( + pages.get("snapshot_matches_ref") is True + and pages.get("title_contract") is True + and page_exact + ) + superseded_landing = ( + repository.get("remote_main_contains_expected") is True + and not exact_remote + and cleanup_complete + ) + authoritative_landing = (exact_remote and current_pages) or superseded_landing + exact_gate_pass = ( + gate.get("valid") is True + and gate.get("status") == "pass" + and gate.get("revision") == exact_revision + ) + + if authoritative_landing and cleanup_complete and exact_gate_pass: + if primary.get("dirty") is True: + append_once( + ownership, + "unrelated_primary_checkout_dirty", + "the current primary checkout is dirty, but immutable remote and cleanup proof already establish this landing", + ) + if superseded_landing and ( + pages.get("snapshot_matches_ref") is not True + or pages.get("title_contract") is not True + or pages.get("source_revision") != repository.get("remote_main_revision") + ): + append_once( + anomalies, + "current_main_unpublished", + "the candidate is landed, but current remote pages does not publish the newer main head", + ) + if public.get("source_is_expected") is False and exact_remote: + append_once( + anomalies, + "public_edge_converging", + "remote pages is exact while the one-shot public edge still serves another source", + ) + elif public.get("contract_ok") is not True and exact_remote: + append_once( + anomalies, + "public_edge_unverified", + "remote pages is exact but the one-shot public read did not prove the edge contract", + ) + if channel.get("valid") is True and channel.get("status") == "delivered": + pass + elif channel.get("valid") is True and channel.get("status") in {"unavailable", "failed"}: + append_once( + missing, + "telegram_delivery_pending", + "deliver the landing result through Telegram when an outbound channel is available", + ) + append_once( + anomalies, + "telegram_runtime_unavailable", + "the supplied channel receipt does not prove outbound Telegram delivery", + ) + else: + append_once( + missing, + "telegram_delivery_unproven", + "a real Telegram message id is still needed to prove user-visible delivery", + ) + short = exact_revision[:12] if exact_revision else "unknown" + if superseded_landing: + summary = f"Landed {short}; a newer main/pages revision now supersedes it and owned cleanup is complete." + elif any(row["code"] == "public_edge_converging" for row in anomalies): + summary = f"Landed {short}; remote main/pages are exact and cleanup is complete while the public edge converges." + else: + summary = f"Landed {short}; remote main/pages are exact and owned cleanup is complete." + return "landed", missing, ownership, anomalies, summary + + remote_is_candidate = exact_remote + if remote_is_candidate: + if not exact_gate_pass: + append_once( + missing, + "gate_receipt_missing" if gate.get("provided") is not True else "landing_gate_failed", + "supply a passing landing-gate receipt bound to the exact candidate", + ) + if not current_pages: + append_once(missing, "publication_pending", "publish remote pages from the exact landed revision") + if run_status != "ok": + append_once(missing, "run_completion_pending", "complete the target run after publication") + if target.get("present") is not False: + append_once(missing, "cleanup_pending", "remove the owned task worktree and branch through the normal cleanup path") + return ( + "blocked", + missing, + ownership, + anomalies, + f"Main contains {exact_revision[:12] if exact_revision else 'the candidate'}, but publication or owned cleanup is incomplete.", + ) + + if repository.get("remote_main_contains_expected") is True: + if not exact_gate_pass: + append_once( + missing, + "gate_receipt_missing" if gate.get("provided") is not True else "landing_gate_failed", + "supply a passing landing-gate receipt bound to the exact candidate", + ) + if run_status != "ok": + append_once(missing, "run_completion_pending", "supply the completed target-run evidence for the superseded candidate") + if target.get("present") is not False: + append_once(missing, "cleanup_pending", "prove that the superseded candidate's owned worktree is removed") + return ( + "blocked", + missing, + ownership, + anomalies, + f"Remote main contains {exact_revision[:12] if exact_revision else 'the candidate'}, but its completed landing receipt is incomplete.", + ) + + if primary.get("dirty") is True: + append_once( + ownership, + "unrelated_primary_checkout_dirty", + "the primary checkout is dirty; land from the owned worktree without disturbing it", + ) + + ready_conditions: list[tuple[str, bool]] = [] + target_present = target.get("present") is True + ready_conditions.append(("target_worktree_missing", target_present)) + if target_present: + ready_conditions.extend( + [ + ("candidate_head_mismatch", target.get("head_revision") == exact_revision), + ("task_worktree_dirty", target.get("dirty") is False), + ("candidate_requires_rebase", target.get("behind") == 0), + ("no_candidate_delta", isinstance(target.get("ahead"), int) and target.get("ahead", 0) > 0), + ] + ) + ready_conditions.extend( + [ + ("local_remote_ref_stale", repository.get("local_main_revision") == repository.get("remote_main_revision")), + ("target_run_not_running", run_status == "running"), + ("task_ownership_unproven", owner_matches), + ("generated_work_orders_stale", project.get("generated_work_orders_fresh") is True), + ("generated_ledgers_stale", project.get("generated_ledgers_fresh") is True), + ] + ) + if gate.get("provided") is not True: + ready_conditions.append(("gate_receipt_missing", False)) + elif gate.get("valid") is not True: + ready_conditions.append(("gate_receipt_invalid", False)) + elif gate.get("status") != "pass": + ready_conditions.append(("landing_gate_failed", False)) + summaries = { + "target_worktree_missing": "restore or identify the owned target worktree", + "candidate_head_mismatch": "make the target worktree name the expected candidate", + "task_worktree_dirty": "commit or otherwise resolve the target worktree dirt before landing", + "local_remote_ref_stale": "refresh and reconcile the local remote-main evidence", + "candidate_requires_rebase": "rebase the candidate onto current remote main", + "no_candidate_delta": "produce a candidate commit ahead of remote main", + "target_run_not_running": "restore a coherent running target heartbeat", + "task_ownership_unproven": "prove that the current agent owns the target run and worktree", + "gate_receipt_missing": "supply an exact-revision landing-gate receipt", + "gate_receipt_invalid": "replace the malformed gate receipt", + "landing_gate_failed": "run and pass the landing gate on the exact candidate", + "generated_work_orders_stale": "regenerate the work-order projection", + "generated_ledgers_stale": "regenerate the corpus ledger indexes", + } + failed = [code for code, ok in ready_conditions if not ok] + if not failed: + append_once(missing, "land_candidate", "run the repository's existing serialized landing path") + return ( + "ready", + missing, + ownership, + anomalies, + f"Candidate {exact_revision[:12] if exact_revision else 'unknown'} is coherent and ready for the existing landing path.", + ) + for code in failed: + append_once(missing, code, summaries[code]) + return ( + "blocked", + missing, + ownership, + anomalies, + f"Candidate {exact_revision[:12] if exact_revision else 'unknown'} is coherent, but required landing evidence or prerequisites are missing.", + ) + + +def observe( + root_hint: Path, + task: str, + revision: str, + remote: str, + site_url: str, + gate_receipt: Path | None, + deployment_receipt: Path | None, + channel_receipt: Path | None, + *, + runner: Runner = command_runner, +) -> tuple[dict[str, object], int]: + root_result = runner( + ["git", "-C", str(root_hint), "rev-parse", "--show-toplevel"], + cwd=root_hint, + env=read_only_env(), + ) + root = Path(root_result.stdout.strip()) if root_result.returncode == 0 else root_hint + hinted_root_matches = ( + root.resolve() == root_hint.resolve() if root_result.returncode == 0 else None + ) + caller_agent = os.environ.get("AGENT_ID") or os.environ.get("LETTA_AGENT_ID") or None + evidence: dict[str, object] = { + "input": { + "agent_id": caller_agent, + "remote": redact_url(remote), + "repository_path": str(root), + "site_url": redact_url(site_url), + "task": task, + }, + "pages": { + "available": None, + "read_error": None, + "snapshot_matches_ref": None, + "snapshot_revision": None, + "source_is_expected": None, + "source_revision": None, + "title_contract": None, + }, + "primary_worktree": live_worktree(runner, None), + "project_status": { + "consistent": None, + "error_count": None, + "generated_ledgers_fresh": None, + "generated_work_orders_fresh": None, + "read_error": None, + "readable": False, + "target_run": { + "agent_id": None, + "phase": None, + "present": None, + "status": None, + "worktree": None, + }, + "target_run_ambiguous": None, + "target_worktree_ambiguous": None, + "warning_count": None, + }, + "public_site": { + "attempted": False, + "contract_ok": None, + "read_error": None, + "source_is_expected": None, + "source_revision": None, + }, + "receipts": { + "channel": read_receipt(channel_receipt, "channel"), + "deployment": read_receipt(deployment_receipt, "deployment"), + "gate": read_receipt(gate_receipt, "gate"), + }, + "repository": { + "candidate_head_stable": None, + "hinted_root_matches": hinted_root_matches, + "changed_paths": None, + "local_main_revision": None, + "read_error": None, + "readable": root_result.returncode == 0, + "remote_main_contains_expected": None, + "remote_main_is_expected": None, + "remote_main_revision": None, + "remote_pages_revision": None, + "remote_refs_readable": None, + "remote_refs_stable": None, + "snapshot_main_matches_ref": None, + "snapshot_main_revision": None, + }, + "target_worktree": live_worktree(runner, None), + } + + if root_result.returncode != 0: + evidence["repository"]["read_error"] = clean_line(root_result) + state, missing, ownership, anomalies, summary = classify(evidence, None) + receipt = { + "anomalies": anomalies, + "evidence": evidence, + "exact_revision": None, + "missing_steps": missing, + "ownership_warnings": ownership, + "plain_summary": summary, + "schema": SCHEMA, + "state": state, + } + return receipt, 2 + + expected = None + if SHA_RE.fullmatch(revision): + expected = one_sha( + git(runner, root, "rev-parse", "--verify", f"{revision}^{{commit}}") + ) + observed_head_first = one_sha(git(runner, root, "rev-parse", "--verify", "HEAD^{commit}")) + primary = primary_root(runner, root) + + refs_command = [ + "ls-remote", + "--heads", + remote, + "refs/heads/main", + "refs/heads/pages", + ] + first_result = git(runner, root, *refs_command, timeout=45) + first_refs = remote_refs(first_result) + first_main = first_refs.get("refs/heads/main") + first_pages = first_refs.get("refs/heads/pages") + + remote_url_result = git(runner, root, "remote", "get-url", remote) + ssh_result = git(runner, root, "config", "--get", "core.sshCommand") + remote_url = remote_url_result.stdout.strip() if remote_url_result.returncode == 0 else "" + ssh_command = ssh_result.stdout.strip() if ssh_result.returncode == 0 else None + snapshot: dict[str, object] = { + "changed_paths": None, + "main_contains_expected": None, + "main_read_error": None, + "main_revision": None, + "page_read_error": None, + "page_revision": None, + "page_source_revision": None, + "page_title_contract": None, + "target_ahead": None, + "target_behind": None, + } + if remote_url and expected is not None: + snapshot = isolated_remote_snapshot( + runner, + root, + remote_url, + ssh_command, + expected, + first_main, + first_pages, + ) + elif not remote_url: + error = clean_line(remote_url_result) + snapshot["main_read_error"] = error + snapshot["page_read_error"] = error + elif expected is None: + snapshot["main_read_error"] = "the expected candidate could not be resolved locally" + + project, target_path = project_observation(runner, root, task, primary) + evidence["project_status"] = project + target = live_worktree(runner, target_path) + primary_live = live_worktree(runner, primary) + evidence["target_worktree"] = target + evidence["primary_worktree"] = primary_live + + repository = evidence["repository"] + repository["read_error"] = snapshot.get("main_read_error") + repository["remote_main_contains_expected"] = snapshot.get("main_contains_expected") + repository["remote_main_is_expected"] = ( + first_main == expected if first_main is not None and expected is not None else None + ) + changed_paths = snapshot.get("changed_paths") + repository["changed_paths"] = changed_paths if isinstance(changed_paths, list) else None + target["behind"] = snapshot.get("target_behind") + target["ahead"] = snapshot.get("target_ahead") + + local_main = one_sha( + git(runner, root, "rev-parse", "--verify", f"refs/remotes/{remote}/main^{{commit}}") + ) + evidence["repository"]["local_main_revision"] = local_main + + site_env = read_only_env( + { + "SITE_SMOKE_URL": site_url, + "SITE_SMOKE_ATTEMPTS": "1", + "SITE_SMOKE_DELAY_SECONDS": "0", + } + ) + if expected is not None: + site_env["SITE_SOURCE_REVISION"] = expected + site_script = root / "tools/site-smoke.sh" + site_result = runner(["bash", str(site_script)], cwd=root, env=site_env, timeout=30) + site_output = "\n".join(part for part in (site_result.stdout, site_result.stderr) if part) + site_source = public_source(site_output) + evidence["public_site"] = { + "attempted": True, + "contract_ok": site_result.returncode == 0, + "read_error": clean_line(site_result) if site_result.returncode != 0 else None, + "source_is_expected": ( + site_source == expected if site_source is not None and expected is not None else None + ), + "source_revision": site_source, + } + + second_result = git(runner, root, *refs_command, timeout=45) + second_refs = remote_refs(second_result) + second_main = second_refs.get("refs/heads/main") + second_pages = second_refs.get("refs/heads/pages") + remote_readable = first_result.returncode == 0 and second_result.returncode == 0 + remote_stable = remote_readable and first_refs == second_refs + observed_head_second = one_sha(git(runner, root, "rev-parse", "--verify", "HEAD^{commit}")) + target_head_second = None + if target.get("present") is True and isinstance(target.get("path"), str): + target_head_second = one_sha( + git(runner, Path(str(target["path"])), "rev-parse", "--verify", "HEAD^{commit}") + ) + + repository = evidence["repository"] + first_candidate_head = ( + target.get("head_revision") + if target.get("present") is True + else observed_head_first + ) + second_candidate_head = ( + target_head_second + if target.get("present") is True + else observed_head_second + ) + repository["candidate_head_stable"] = ( + first_candidate_head == second_candidate_head + if isinstance(first_candidate_head, str) and isinstance(second_candidate_head, str) + else None + ) + repository["remote_main_revision"] = second_main + repository["remote_pages_revision"] = second_pages + repository["remote_refs_readable"] = remote_readable + repository["remote_refs_stable"] = remote_stable + snapshot_main = snapshot.get("main_revision") + repository["snapshot_main_revision"] = snapshot_main + repository["snapshot_main_matches_ref"] = ( + snapshot_main == second_main + if isinstance(snapshot_main, str) and isinstance(second_main, str) + else None + ) + if expected is not None and remote_stable and second_main is not None: + repository["remote_main_is_expected"] = second_main == expected + if second_main == expected: + repository["remote_main_contains_expected"] = True + elif repository["snapshot_main_matches_ref"] is True: + repository["remote_main_contains_expected"] = snapshot.get( + "main_contains_expected" + ) + + page_commit = snapshot.get("page_revision") + page_source = snapshot.get("page_source_revision") + page_error = snapshot.get("page_read_error") + page_title_ok = snapshot.get("page_title_contract") + evidence["pages"] = { + "available": ( + True + if isinstance(page_commit, str) + else False + if second_pages is None and remote_stable + else None + ), + "read_error": page_error, + "snapshot_matches_ref": ( + page_commit == second_pages + if isinstance(page_commit, str) and isinstance(second_pages, str) + else None + ), + "snapshot_revision": page_commit, + "source_is_expected": ( + page_source == expected + if isinstance(page_source, str) and expected is not None + else None + ), + "source_revision": page_source, + "title_contract": page_title_ok, + } + + state, missing, ownership, anomalies, summary = classify(evidence, expected) + receipt = { + "anomalies": anomalies, + "evidence": evidence, + "exact_revision": expected, + "missing_steps": missing, + "ownership_warnings": ownership, + "plain_summary": summary, + "schema": SCHEMA, + "state": state, + } + return receipt, {"ready": 0, "landed": 0, "blocked": 1, "inconsistent": 2}[state] + + +def main() -> int: + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--root", type=Path, default=Path.cwd()) + parser.add_argument("--task", required=True, help="owned task/worktree id") + parser.add_argument("--revision", required=True, help="expected candidate Git revision") + parser.add_argument("--remote", default="origin", help="remote carrying main and pages") + parser.add_argument("--site-url", default=os.environ.get("SITE_SMOKE_URL", DEFAULT_SITE_URL)) + parser.add_argument("--gate-receipt", type=Path) + parser.add_argument("--deployment-receipt", type=Path) + parser.add_argument("--channel-receipt", type=Path) + args = parser.parse_args() + try: + receipt, status = observe( + args.root, + args.task, + args.revision, + args.remote, + args.site_url, + args.gate_receipt, + args.deployment_receipt, + args.channel_receipt, + ) + except Exception as exc: # Last-resort stable failure packet; never emit a traceback. + receipt = { + "anomalies": [fact("observer_internal_error", f"the observer could not complete: {type(exc).__name__}")], + "evidence": {}, + "exact_revision": None, + "missing_steps": [], + "ownership_warnings": [], + "plain_summary": "The one-shot observation failed before a safe conclusion was possible.", + "schema": SCHEMA, + "state": "inconsistent", + } + status = 2 + print(json.dumps(receipt, indent=2, sort_keys=True)) + return status + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/.agents/skills/observing-misaligned-landings/tests/interpret-anomalies.test.mjs b/.agents/skills/observing-misaligned-landings/tests/interpret-anomalies.test.mjs new file mode 100644 --- /dev/null +++ b/.agents/skills/observing-misaligned-landings/tests/interpret-anomalies.test.mjs @@ -0,0 +1,320 @@ +import assert from "node:assert/strict"; +import http from "node:http"; +import test from "node:test"; + +import { + INTERPRETATION_SCHEMA, + MODEL, + SPECIALIST_NAME, + buildPrompt, + findOrCreateSpecialist, + interpretationReceipt, + interpret, + needsInterpretation, + validateReceipt, +} from "../scripts/interpret-anomalies.mjs"; + +function receipt(overrides = {}) { + return { + schema: "network.comind.misaligned.landing-observation/v2", + state: "inconsistent", + exact_revision: "a".repeat(40), + plain_summary: "Landing evidence contradicts itself.", + missing_steps: [], + ownership_warnings: [], + anomalies: [{ code: "remote_refs_moved", summary: "Remote refs moved." }], + evidence: { + repository: { + hinted_root_matches: true, + remote_main_revision: "a".repeat(40), + remote_pages_revision: "b".repeat(40), + remote_refs_readable: true, + remote_refs_stable: false, + secret: "must-not-cross-boundary", + }, + primary_worktree: { dirty: false, path: "/private/checkout" }, + target_worktree: { + ahead: 0, + behind: 0, + dirty: false, + path: "/private/task", + path_escape: "/outside/repository", + present: true, + }, + project_status: { + consistent: true, + target_run: { present: true, phase: "landing", raw: "not allowed" }, + }, + receipts: { + gate: { provided: true, valid: true, path: "/secret/gate.json" }, + deployment: { provided: false }, + channel: { provided: false }, + }, + pages: { available: true }, + public_site: { attempted: false }, + }, + ...overrides, + }; +} + +test("receipt validation rejects unsupported states", () => { + assert.throws( + () => validateReceipt(receipt({ state: "guessing" })), + /state must be ready, blocked, landed, or inconsistent/, + ); +}); + +test("receipt validation rejects non-object evidence", () => { + assert.throws( + () => validateReceipt(receipt({ evidence: null })), + /evidence must be a JSON object/, + ); +}); + +test("only non-benign anomalies need interpretation", () => { + const clean = receipt({ state: "landed", anomalies: [] }); + assert.equal(needsInterpretation(clean), false); + const converging = receipt({ + state: "landed", + anomalies: [ + { code: "public_edge_converging", summary: "The public edge is converging." }, + ], + }); + assert.equal(needsInterpretation(converging), false); + assert.equal(needsInterpretation(receipt()), true); +}); + +test("interpretation receipt strips paths and arbitrary evidence", () => { + const projected = interpretationReceipt(receipt()); + const serialized = JSON.stringify(projected); + assert.equal(projected.state, "inconsistent"); + assert.equal(projected.evidence.target_worktree.path_escape_detected, true); + assert.equal(projected.evidence.repository.remote_refs_stable, false); + assert.equal(projected.evidence.receipts.gate.valid, true); + assert.equal(serialized.includes("/private"), false); + assert.equal(serialized.includes("/outside"), false); + assert.equal(serialized.includes("/secret"), false); + assert.equal(serialized.includes("must-not-cross-boundary"), false); + assert.equal(serialized.includes("not allowed"), false); +}); + +test("prompt freezes classifier authority", () => { + const prompt = buildPrompt(receipt()); + assert.match(prompt, /deterministic state is inconsistent/); + assert.match(prompt, /must not change it/); + assert.match(prompt, /Do not use tools/); + assert.match(prompt, /empty evidence is unknown/); + assert.match(prompt, /Do not recommend polling/); + assert.match(prompt, /MINIMIZED LANDING RECEIPT/); +}); + +test("specialist lookup reuses the exact retained name", async () => { + const calls = []; + const client = { + agents: { + async list(query) { + calls.push(["list", query]); + return [ + { id: "agent-near", name: `${SPECIALIST_NAME} copy` }, + { id: "agent-exact", name: SPECIALIST_NAME }, + ]; + }, + }, + async createAgent() { + calls.push(["create"]); + throw new Error("must not create"); + }, + }; + assert.deepEqual(await findOrCreateSpecialist(client), { + agentId: "agent-exact", + created: false, + }); + assert.deepEqual(calls, [["list", { name: SPECIALIST_NAME, limit: 100 }]]); +}); + +test("specialist creation is empty-memory, zero-tool, and persistent", async () => { + const calls = []; + const client = { + agents: { + async list(query) { + calls.push(["list", query]); + return []; + }, + }, + async createAgent(options) { + calls.push(["create", options]); + return "agent-created"; + }, + }; + assert.deepEqual(await findOrCreateSpecialist(client), { + agentId: "agent-created", + created: true, + }); + const options = calls[1][1]; + assert.equal(options.name, SPECIALIST_NAME); + assert.equal(options.model, MODEL); + assert.equal(options.memfs, false); + assert.equal(options.hidden, undefined); + assert.deepEqual(options.memory, []); + assert.deepEqual(options.baseTools, []); + assert.deepEqual(Object.keys(options).sort(), [ + "baseTools", + "description", + "memfs", + "memory", + "model", + "name", + "systemPrompt", + ]); + assert.equal(calls.some(([kind]) => kind === "delete"), false); +}); + +test("installed SDK translates specialist creation to an empty-memory zero-tool agent", async (t) => { + let LettaAgentClient; + try { + ({ LettaAgentClient } = await import("@letta-ai/letta-agent-sdk")); + } catch (error) { + if ( + error?.code === "ERR_MODULE_NOT_FOUND" && + String(error.message).includes("@letta-ai/letta-agent-sdk") + ) { + t.skip("pinned SDK dependencies are not installed in this checkout"); + return; + } + throw error; + } + + let observedRequest = null; + const server = http.createServer((request, response) => { + const chunks = []; + request.on("data", (chunk) => chunks.push(chunk)); + request.on("end", () => { + observedRequest = { + body: JSON.parse(Buffer.concat(chunks).toString("utf8")), + method: request.method, + url: request.url, + }; + response.writeHead(200, { "content-type": "application/json" }); + response.end(JSON.stringify({ id: "agent-sdk-contract", name: SPECIALIST_NAME })); + }); + }); + await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); + const address = server.address(); + assert.ok(address && typeof address === "object"); + + try { + const client = new LettaAgentClient({ + apiBaseUrl: `http://127.0.0.1:${address.port}`, + apiKey: "hermetic-contract-key", + backend: "cloud", + }); + const specialist = await findOrCreateSpecialist({ + agents: { list: async () => [] }, + createAgent: (options) => client.createAgent(options), + }); + assert.deepEqual(specialist, { agentId: "agent-sdk-contract", created: true }); + } finally { + await new Promise((resolve) => server.close(resolve)); + } + + assert.ok(observedRequest); + assert.equal(observedRequest.method, "POST"); + assert.equal(observedRequest.url, "/v1/agents/"); + assert.equal(observedRequest.body.name, SPECIALIST_NAME); + assert.equal(observedRequest.body.model, MODEL); + assert.equal(observedRequest.body.hidden, undefined); + assert.deepEqual(observedRequest.body.memory_blocks, []); + assert.deepEqual(observedRequest.body.tools, []); + assert.equal(observedRequest.body.include_base_tools, false); + assert.equal(observedRequest.body.include_base_tool_rules, false); + assert.deepEqual(observedRequest.body.tags, ["origin:letta-code"]); + assert.match(observedRequest.body.system, /no tools, skills, repository access/); +}); + +test("duplicate exact-name specialists fail closed", async () => { + const client = { + agents: { + async list() { + return [ + { id: "one", name: SPECIALIST_NAME }, + { id: "two", name: SPECIALIST_NAME }, + ]; + }, + }, + }; + await assert.rejects( + findOrCreateSpecialist(client), + /more than one Letta agent is named/, + ); +}); + +test("clean and benign receipts avoid SDK loading", async () => { + let loaded = false; + for (const value of [ + receipt({ state: "landed", anomalies: [] }), + receipt({ + state: "landed", + anomalies: [ + { code: "public_edge_converging", summary: "The public edge is converging." }, + ], + }), + ]) { + const result = await interpret(value, {}, async () => { + loaded = true; + throw new Error("must not load SDK"); + }); + assert.equal(result.schema, INTERPRETATION_SCHEMA); + assert.equal(result.status, "not-needed"); + assert.equal(result.interpretation, null); + } + assert.equal(loaded, false); +}); + +test("anomaly interpretation uses retained specialist and a fresh zero-authority conversation", async () => { + const calls = []; + class FakeClient { + constructor(options) { + calls.push(["construct", options]); + this.agents = { + list: async (query) => { + calls.push(["list", query]); + return [{ id: "agent-observer", name: SPECIALIST_NAME }]; + }, + }; + } + + async prompt(prompt, agentId, options) { + calls.push(["prompt", prompt, agentId, options]); + return { + success: true, + result: "The remote moved during observation.", + conversationId: "conv-one-shot", + stopReason: "end_turn", + }; + } + } + const result = await interpret( + receipt(), + { LETTA_API_KEY: "key", LETTA_BASE_URL: "https://letta.example" }, + async () => ({ LettaAgentClient: FakeClient }), + ); + assert.equal(result.status, "ok"); + assert.equal(result.agent_id, "agent-observer"); + assert.equal(result.agent_name, SPECIALIST_NAME); + assert.equal(result.agent_created, false); + assert.equal(result.conversation_id, "conv-one-shot"); + const promptCall = calls.find(([kind]) => kind === "prompt"); + assert.ok(promptCall); + assert.equal(promptCall[2], "agent-observer"); + assert.deepEqual(promptCall[3].allowedTools, []); + assert.deepEqual(promptCall[3].skillSources, []); + assert.deepEqual(promptCall[3].tools, []); + assert.deepEqual(promptCall[3].toolset, { base: "none" }); + assert.equal(promptCall[3].permissionMode, "strict"); + assert.equal(promptCall[3].stateless, true); + assert.equal(Object.hasOwn(promptCall[3], "model"), false); + assert.equal(Object.hasOwn(promptCall[3], "systemInfoReminder"), false); + assert.equal(JSON.stringify(promptCall).includes("/private"), false); + assert.equal(calls.some(([kind]) => kind === "delete"), false); + assert.equal(calls.some(([kind]) => kind === "resume"), false); +});