compass-code 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (137) hide show
  1. compass_cli/__init__.py +0 -0
  2. compass_cli/commands/__init__.py +0 -0
  3. compass_cli/commands/ingest.py +310 -0
  4. compass_cli/commands/mcp.py +25 -0
  5. compass_cli/commands/query.py +181 -0
  6. compass_cli/commands/serve.py +123 -0
  7. compass_cli/commands/setup.py +171 -0
  8. compass_cli/display.py +231 -0
  9. compass_cli/errors.py +30 -0
  10. compass_cli/main.py +54 -0
  11. compass_cli/progress.py +191 -0
  12. compass_cli/result_views.py +389 -0
  13. compass_cli/types.py +41 -0
  14. compass_code-0.1.0.dist-info/METADATA +72 -0
  15. compass_code-0.1.0.dist-info/RECORD +137 -0
  16. compass_code-0.1.0.dist-info/WHEEL +4 -0
  17. compass_code-0.1.0.dist-info/entry_points.txt +2 -0
  18. compass_core/__init__.py +1 -0
  19. compass_core/contract/__init__.py +6 -0
  20. compass_core/contract/errors.py +116 -0
  21. compass_core/contract/models.py +204 -0
  22. compass_core/contract/params.py +99 -0
  23. compass_core/contract/results.py +370 -0
  24. compass_core/contract/serialize.py +59 -0
  25. compass_core/contract/types.py +76 -0
  26. compass_core/errors.py +148 -0
  27. compass_core/graph/__init__.py +0 -0
  28. compass_core/graph/db.py +205 -0
  29. compass_core/graph/schema.py +165 -0
  30. compass_core/graph/stored_ids.py +133 -0
  31. compass_core/graph/writer.py +482 -0
  32. compass_core/index/__init__.py +1 -0
  33. compass_core/index/freshness.py +55 -0
  34. compass_core/index/locate.py +155 -0
  35. compass_core/index/metadata.py +107 -0
  36. compass_core/ir/__init__.py +0 -0
  37. compass_core/ir/graph.py +65 -0
  38. compass_core/ir/models.py +75 -0
  39. compass_core/languages/__init__.py +1 -0
  40. compass_core/languages/base.py +26 -0
  41. compass_core/languages/python/__init__.py +6 -0
  42. compass_core/languages/python/extractor.py +670 -0
  43. compass_core/languages/python/import_resolver.py +107 -0
  44. compass_core/languages/registry.py +89 -0
  45. compass_core/logger.py +42 -0
  46. compass_core/phases/__init__.py +0 -0
  47. compass_core/phases/base.py +58 -0
  48. compass_core/phases/discovery.py +167 -0
  49. compass_core/phases/parse.py +80 -0
  50. compass_core/phases/persistence.py +33 -0
  51. compass_core/phases/pipeline.py +152 -0
  52. compass_core/phases/resolution.py +572 -0
  53. compass_core/phases/symbol_table.py +36 -0
  54. compass_core/phases/validation.py +76 -0
  55. compass_core/progress.py +45 -0
  56. compass_core/py.typed +0 -0
  57. compass_core/query/__init__.py +1 -0
  58. compass_core/query/cypher.py +92 -0
  59. compass_core/query/detail.py +241 -0
  60. compass_core/query/graph_map.py +127 -0
  61. compass_core/query/impact.py +273 -0
  62. compass_core/query/impact_walk.py +352 -0
  63. compass_core/query/overview.py +221 -0
  64. compass_core/query/references.py +235 -0
  65. compass_core/query/rows.py +378 -0
  66. compass_core/query/search.py +183 -0
  67. compass_core/query/status.py +49 -0
  68. compass_core/query/walk_queries.py +202 -0
  69. compass_core/render.py +408 -0
  70. compass_core/settings.py +61 -0
  71. compass_core/shared_types.py +78 -0
  72. compass_mcp/__init__.py +0 -0
  73. compass_mcp/guide.py +45 -0
  74. compass_mcp/py.typed +0 -0
  75. compass_mcp/server.py +261 -0
  76. compass_server/__init__.py +5 -0
  77. compass_server/errors.py +84 -0
  78. compass_server/main.py +42 -0
  79. compass_server/py.typed +0 -0
  80. compass_server/routers/__init__.py +0 -0
  81. compass_server/routers/query.py +182 -0
  82. compass_server/settings.py +37 -0
  83. compass_server/static/404.html +1 -0
  84. compass_server/static/_next/static/chunks/1629039a.eed2a06658ec4f9c.js +1 -0
  85. compass_server/static/_next/static/chunks/1ff282bf-bb7c483245264fc9.js +1 -0
  86. compass_server/static/_next/static/chunks/223.f881a22f446259bf.js +508 -0
  87. compass_server/static/_next/static/chunks/51fa5c19.6396973222c9d6fd.js +485 -0
  88. compass_server/static/_next/static/chunks/556.443c1682b6b20128.js +1 -0
  89. compass_server/static/_next/static/chunks/684-1aa0170f59baf77e.js +1 -0
  90. compass_server/static/_next/static/chunks/92e71660.3a42d4f70d017951.js +342 -0
  91. compass_server/static/_next/static/chunks/937-8692224bb6d1b605.js +1 -0
  92. compass_server/static/_next/static/chunks/app/_not-found/page-2c96ddf295eb6a86.js +1 -0
  93. compass_server/static/_next/static/chunks/app/layout-4bd0ba4a7d18aff9.js +1 -0
  94. compass_server/static/_next/static/chunks/app/page-5376a0a98bbd1faa.js +1 -0
  95. compass_server/static/_next/static/chunks/framework-96dcd958cfe08bd4.js +1 -0
  96. compass_server/static/_next/static/chunks/main-6dee8e626b16731a.js +1 -0
  97. compass_server/static/_next/static/chunks/main-app-460e8bc670818718.js +1 -0
  98. compass_server/static/_next/static/chunks/pages/_app-638a3e7363f92b80.js +1 -0
  99. compass_server/static/_next/static/chunks/pages/_error-6a72dbbb45cae743.js +1 -0
  100. compass_server/static/_next/static/chunks/polyfills-42372ed130431b0a.js +1 -0
  101. compass_server/static/_next/static/chunks/webpack-597057bf48ce4111.js +1 -0
  102. compass_server/static/_next/static/css/1b0fbfd8dd653f37.css +3 -0
  103. compass_server/static/_next/static/ctUZeD9K7jQUgLqmBas2L/_buildManifest.js +1 -0
  104. compass_server/static/_next/static/ctUZeD9K7jQUgLqmBas2L/_ssgManifest.js +1 -0
  105. compass_server/static/_next/static/media/0086f8992871c45b-s.woff2 +0 -0
  106. compass_server/static/_next/static/media/034d78ad42e9620c-s.woff2 +0 -0
  107. compass_server/static/_next/static/media/03b436aa846269de-s.woff2 +0 -0
  108. compass_server/static/_next/static/media/0484562807a97172-s.p.woff2 +0 -0
  109. compass_server/static/_next/static/media/08aedeceaf1dcd57-s.woff2 +0 -0
  110. compass_server/static/_next/static/media/0aa834ed78bf6d07-s.woff2 +0 -0
  111. compass_server/static/_next/static/media/29a4aea02fdee119-s.woff2 +0 -0
  112. compass_server/static/_next/static/media/29e7bbdce9332268-s.woff2 +0 -0
  113. compass_server/static/_next/static/media/36008747766f78c6-s.woff2 +0 -0
  114. compass_server/static/_next/static/media/39969fcf98a3026e-s.woff2 +0 -0
  115. compass_server/static/_next/static/media/4de1fea1a954a5b6-s.p.woff2 +0 -0
  116. compass_server/static/_next/static/media/5c0c2bcbaa4149ca-s.p.woff2 +0 -0
  117. compass_server/static/_next/static/media/67957d42bae0796d-s.woff2 +0 -0
  118. compass_server/static/_next/static/media/6d38f9d4e0f4772b-s.woff2 +0 -0
  119. compass_server/static/_next/static/media/6d664cce900333ee-s.p.woff2 +0 -0
  120. compass_server/static/_next/static/media/886030b0b59bc5a7-s.woff2 +0 -0
  121. compass_server/static/_next/static/media/8888a3826f4a3af4-s.p.woff2 +0 -0
  122. compass_server/static/_next/static/media/939c4f875ee75fbb-s.woff2 +0 -0
  123. compass_server/static/_next/static/media/a1386beebedccca4-s.woff2 +0 -0
  124. compass_server/static/_next/static/media/ab00a911ac2adf48-s.woff2 +0 -0
  125. compass_server/static/_next/static/media/b957ea75a84b6ea7-s.p.woff2 +0 -0
  126. compass_server/static/_next/static/media/bb3ef058b751a6ad-s.p.woff2 +0 -0
  127. compass_server/static/_next/static/media/c3bc380753a8436c-s.woff2 +0 -0
  128. compass_server/static/_next/static/media/cce080f35d014443-s.woff2 +0 -0
  129. compass_server/static/_next/static/media/db911767852bc875-s.woff2 +0 -0
  130. compass_server/static/_next/static/media/eafabf029ad39a43-s.p.woff2 +0 -0
  131. compass_server/static/_next/static/media/f10b8e9d91f3edcb-s.woff2 +0 -0
  132. compass_server/static/_next/static/media/f911b923c6adde36-s.woff2 +0 -0
  133. compass_server/static/_next/static/media/fe0777f1195381cb-s.woff2 +0 -0
  134. compass_server/static/index.html +1 -0
  135. compass_server/static/index.txt +25 -0
  136. compass_server/web_bundle.py +27 -0
  137. compass_server/web_limits.py +48 -0
@@ -0,0 +1,182 @@
1
+ """``/api`` routes: thin HTTP adapters over the read-only query layer.
2
+
3
+ Each route parses its parameters, calls one ``compass_core.query`` function and returns
4
+ its ``compass_core.contract`` result. Status codes for failures come from
5
+ ``ERROR_MAPPINGS``, the table every adapter shares.
6
+ """
7
+
8
+ from __future__ import annotations
9
+
10
+ from collections.abc import Iterator
11
+ from typing import Annotated, Any, TypeVar
12
+
13
+ from fastapi import APIRouter, Depends, Query, Response
14
+
15
+ from compass_core.contract.errors import ERROR_MAPPINGS, ErrorResponse
16
+ from compass_core.contract.models import IndexStatus
17
+ from compass_core.contract.params import (
18
+ DEFAULT_IMPACT_DEPTH,
19
+ DEFAULT_LIMIT,
20
+ DEFAULT_MIN_CONFIDENCE,
21
+ MAX_DEPTH,
22
+ MAX_LIMIT,
23
+ MAX_TEXT_LENGTH,
24
+ ImpactParams,
25
+ SearchParams,
26
+ )
27
+ from compass_core.contract.results import (
28
+ AmbiguousReference,
29
+ GraphMap,
30
+ ImpactResult,
31
+ Lookup,
32
+ NodeDetail,
33
+ OverviewResult,
34
+ SearchResult,
35
+ SymbolNotFound,
36
+ )
37
+ from compass_core.contract.serialize import to_json
38
+ from compass_core.errors import ErrorCode
39
+ from compass_core.graph.db import GraphDB
40
+ from compass_core.index.locate import IndexLocation, locate_index
41
+ from compass_core.query.detail import describe
42
+ from compass_core.query.graph_map import graph_map
43
+ from compass_core.query.impact import impact
44
+ from compass_core.query.overview import overview
45
+ from compass_core.query.search import find_symbols
46
+ from compass_core.query.status import index_status
47
+ from compass_core.shared_types import SymbolKind
48
+
49
+ router = APIRouter(tags=["query"])
50
+
51
+ R = TypeVar("R")
52
+
53
+ _AMBIGUOUS_STATUS = ERROR_MAPPINGS[ErrorCode.AMBIGUOUS].http_status
54
+ _NOT_FOUND_STATUS = ERROR_MAPPINGS[ErrorCode.NOT_FOUND].http_status
55
+ _ERRORS: dict[int | str, dict[str, Any]] = {
56
+ ERROR_MAPPINGS[ErrorCode.INVALID_ARGUMENT].http_status: {
57
+ "model": ErrorResponse,
58
+ "description": "Invalid argument",
59
+ },
60
+ ERROR_MAPPINGS[ErrorCode.INDEX_NOT_FOUND].http_status: {
61
+ "model": ErrorResponse,
62
+ "description": "Index missing, busy or incompatible",
63
+ },
64
+ ERROR_MAPPINGS[ErrorCode.QUERY_TIMEOUT].http_status: {
65
+ "model": ErrorResponse,
66
+ "description": "Query timed out",
67
+ },
68
+ }
69
+ _LOOKUP_ERRORS: dict[int | str, dict[str, Any]] = {
70
+ _NOT_FOUND_STATUS: {"model": SymbolNotFound, "description": "Reference matched nothing"},
71
+ _AMBIGUOUS_STATUS: {
72
+ "model": AmbiguousReference,
73
+ "description": "Reference matched several symbols",
74
+ },
75
+ **_ERRORS,
76
+ }
77
+
78
+
79
+ def get_index() -> IndexLocation:
80
+ """FastAPI dependency for the index; the lookup rule lives in ``locate_index``.
81
+
82
+ Returns:
83
+ The index location.
84
+
85
+ Raises:
86
+ IndexNotFoundError: If no index can be found.
87
+ IndexIncompatibleError: If the index must be rebuilt with ``compass ingest``.
88
+ """
89
+ return locate_index()
90
+
91
+
92
+ def get_db(location: Annotated[IndexLocation, Depends(get_index)]) -> Iterator[GraphDB]:
93
+ """Yield a read-only database handle that is always closed afterwards.
94
+
95
+ Args:
96
+ location: The located index.
97
+
98
+ Yields:
99
+ A read-only ``GraphDB``.
100
+ """
101
+ with GraphDB(location.db_path, read_only=True) as db:
102
+ yield db
103
+
104
+
105
+ def _lookup_response(result: Lookup[R]) -> R | Response:
106
+ """Return a found result as is; an ambiguous or missing reference as its status code.
107
+
108
+ Args:
109
+ result: What a reference-taking operation returned.
110
+
111
+ Returns:
112
+ ``result`` itself, or a JSON response with the status ``ERROR_MAPPINGS`` gives
113
+ ``AMBIGUOUS`` or ``NOT_FOUND`` and the outcome as its body.
114
+
115
+ Example:
116
+ ``_lookup_response(SymbolNotFound(reference="x", suggestions=()))`` is a 404 whose
117
+ body is ``{"outcome":"not_found","reference":"x","suggestions":[]}``.
118
+ """
119
+ if isinstance(result, AmbiguousReference):
120
+ status = _AMBIGUOUS_STATUS
121
+ elif isinstance(result, SymbolNotFound):
122
+ status = _NOT_FOUND_STATUS
123
+ else:
124
+ return result
125
+ return Response(to_json(result), status_code=status, media_type="application/json")
126
+
127
+
128
+ Location = Annotated[IndexLocation, Depends(get_index)]
129
+ Db = Annotated[GraphDB, Depends(get_db)]
130
+ # Free text: 1..MAX_TEXT_LENGTH characters with at least one non-whitespace character;
131
+ # anything else is a 422 INVALID_ARGUMENT naming the parameter.
132
+ _TEXT = Query(min_length=1, max_length=MAX_TEXT_LENGTH, pattern=r"\S")
133
+
134
+
135
+ @router.get("/search", response_model=SearchResult, responses=_ERRORS)
136
+ def search(
137
+ db: Db,
138
+ location: Location,
139
+ q: Annotated[str, _TEXT],
140
+ kind: SymbolKind | None = None,
141
+ limit: Annotated[int, Query(ge=1, le=MAX_LIMIT)] = DEFAULT_LIMIT,
142
+ ) -> SearchResult:
143
+ """Search files, classes, functions and methods by name."""
144
+ return find_symbols(db, location, SearchParams(query=q, kind=kind, limit=limit))
145
+
146
+
147
+ @router.get("/impact", response_model=ImpactResult, responses=_LOOKUP_ERRORS)
148
+ def impact_of(
149
+ db: Db,
150
+ location: Location,
151
+ ref: Annotated[str, _TEXT],
152
+ depth: Annotated[int, Query(ge=1, le=MAX_DEPTH)] = DEFAULT_IMPACT_DEPTH,
153
+ min_confidence: Annotated[float, Query(ge=0, le=1)] = DEFAULT_MIN_CONFIDENCE,
154
+ limit: Annotated[int, Query(ge=1, le=MAX_LIMIT)] = DEFAULT_LIMIT,
155
+ ) -> ImpactResult | Response:
156
+ """List what may be affected by changing a file or symbol."""
157
+ params = ImpactParams(depth=depth, min_confidence=min_confidence, limit=limit)
158
+ return _lookup_response(impact(db, location, ref, params))
159
+
160
+
161
+ @router.get("/status", response_model=IndexStatus, responses=_ERRORS)
162
+ def status(db: Db, location: Location) -> IndexStatus:
163
+ """Describe the index: which repository, when it was built and how many files changed since."""
164
+ return index_status(location, db)
165
+
166
+
167
+ @router.get("/describe", response_model=NodeDetail, responses=_LOOKUP_ERRORS)
168
+ def describe_node(db: Db, location: Location, ref: Annotated[str, _TEXT]) -> NodeDetail | Response:
169
+ """Describe one file, class, function or method: docstring, source and neighbours."""
170
+ return _lookup_response(describe(db, location, ref))
171
+
172
+
173
+ @router.get("/overview", response_model=OverviewResult, responses=_ERRORS)
174
+ def repo_overview(db: Db, location: Location) -> OverviewResult:
175
+ """Summarise the index: totals, entry points and ranked hot spots."""
176
+ return overview(db, location)
177
+
178
+
179
+ @router.get("/graph/map", response_model=GraphMap, responses=_ERRORS)
180
+ def graph(db: Db) -> GraphMap:
181
+ """Every file, class, function and method, and the edges between them, for drawing."""
182
+ return graph_map(db)
@@ -0,0 +1,37 @@
1
+ """Settings of the HTTP server: where it binds and which frontend may call it."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from pydantic import Field, computed_field
6
+
7
+ from compass_core.settings import Settings
8
+
9
+
10
+ class ServerSettings(Settings):
11
+ """Engine settings plus the server's own, from the same environment and ``.env``.
12
+
13
+ Attributes:
14
+ API_HOST: Host the FastAPI server binds to.
15
+ API_PORT: Port the FastAPI server listens on.
16
+ FRONTEND_HOST: Host of the frontend dev server.
17
+ FRONTEND_PORT: Port of the frontend dev server.
18
+ FRONTEND_URL: Origin allowed by CORS, built from the two fields above.
19
+
20
+ Example:
21
+ ``API_PORT=9000 compass serve`` gives ``ServerSettings().API_PORT == 9000``;
22
+ the defaults give ``FRONTEND_URL == "http://localhost:3000"``.
23
+ """
24
+
25
+ API_HOST: str = Field(default="127.0.0.1", description="Host the FastAPI server binds to")
26
+ API_PORT: int = Field(default=8000, description="Port the FastAPI server listens on")
27
+
28
+ FRONTEND_HOST: str = Field(default="localhost", description="Host of the frontend dev server")
29
+ FRONTEND_PORT: int = Field(default=3000, description="Port of the frontend dev server")
30
+
31
+ @computed_field # type: ignore[prop-decorator] # known mypy/pydantic limitation: mypy flags any decorator stacked on @property before the pydantic plugin can special-case @computed_field
32
+ @property
33
+ def FRONTEND_URL(self) -> str:
34
+ return f"http://{self.FRONTEND_HOST}:{self.FRONTEND_PORT}"
35
+
36
+
37
+ server_settings = ServerSettings()
@@ -0,0 +1 @@
1
+ <!DOCTYPE html><!--ctUZeD9K7jQUgLqmBas2L--><html lang="en" class="__variable_97b0d3 __variable_c19f6d __variable_cf84ab __variable_4dc837 h-full"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" href="/_next/static/media/0484562807a97172-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/4de1fea1a954a5b6-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/5c0c2bcbaa4149ca-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/6d664cce900333ee-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/8888a3826f4a3af4-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/b957ea75a84b6ea7-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/bb3ef058b751a6ad-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="preload" href="/_next/static/media/eafabf029ad39a43-s.p.woff2" as="font" crossorigin="" type="font/woff2"/><link rel="stylesheet" href="/_next/static/css/1b0fbfd8dd653f37.css" data-precedence="next"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/webpack-597057bf48ce4111.js"/><script src="/_next/static/chunks/1ff282bf-bb7c483245264fc9.js" async=""></script><script src="/_next/static/chunks/937-8692224bb6d1b605.js" async=""></script><script src="/_next/static/chunks/main-app-460e8bc670818718.js" async=""></script><meta name="robots" content="noindex"/><meta name="next-size-adjust" content=""/><title>404: This page could not be found.</title><title>Code Compass</title><meta name="description" content="Visualize your codebase as a knowledge graph"/><script>(function(){try{var s=localStorage.getItem("compass-theme");var t=s==="light"||s==="dark"?s:(window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light");document.documentElement.dataset.theme=t}catch(e){document.documentElement.dataset.theme="light"}})();</script><script src="/_next/static/chunks/polyfills-42372ed130431b0a.js" noModule=""></script></head><body class="font-sans h-svh overflow-hidden flex flex-col"><div hidden=""><!--$--><!--/$--></div><div style="font-family:system-ui,&quot;Segoe UI&quot;,Roboto,Helvetica,Arial,sans-serif,&quot;Apple Color Emoji&quot;,&quot;Segoe UI Emoji&quot;;height:100vh;text-align:center;display:flex;flex-direction:column;align-items:center;justify-content:center"><div><style>body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}</style><h1 class="next-error-h1" style="display:inline-block;margin:0 20px 0 0;padding:0 23px 0 0;font-size:24px;font-weight:500;vertical-align:top;line-height:49px">404</h1><div style="display:inline-block"><h2 style="font-size:14px;font-weight:400;line-height:49px;margin:0">This page could not be found.</h2></div></div></div><!--$--><!--/$--><script src="/_next/static/chunks/webpack-597057bf48ce4111.js" id="_R_" async=""></script><script>(self.__next_f=self.__next_f||[]).push([0])</script><script>self.__next_f.push([1,"1:\"$Sreact.fragment\"\n2:I[42712,[],\"\"]\n3:I[63566,[],\"\"]\n4:I[4373,[],\"OutletBoundary\"]\n6:I[10656,[],\"AsyncMetadataOutlet\"]\n8:I[4373,[],\"ViewportBoundary\"]\na:I[4373,[],\"MetadataBoundary\"]\nb:\"$Sreact.suspense\"\nd:I[22388,[],\"\"]\n:HL[\"/_next/static/media/0484562807a97172-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/4de1fea1a954a5b6-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/5c0c2bcbaa4149ca-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/6d664cce900333ee-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/8888a3826f4a3af4-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/b957ea75a84b6ea7-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/bb3ef058b751a6ad-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/media/eafabf029ad39a43-s.p.woff2\",\"font\",{\"crossOrigin\":\"\",\"type\":\"font/woff2\"}]\n:HL[\"/_next/static/css/1b0fbfd8dd653f37.css\",\"style\"]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"b\":\"ctUZeD9K7jQUgLqmBas2L\",\"p\":\"\",\"c\":[\"\",\"_not-found\"],\"i\":false,\"f\":[[[\"\",{\"children\":[\"/_not-found\",{\"children\":[\"__PAGE__\",{}]}]},\"$undefined\",\"$undefined\",true],[\"\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"link\",\"0\",{\"rel\":\"stylesheet\",\"href\":\"/_next/static/css/1b0fbfd8dd653f37.css\",\"precedence\":\"next\",\"crossOrigin\":\"$undefined\",\"nonce\":\"$undefined\"}]],[\"$\",\"html\",null,{\"lang\":\"en\",\"className\":\"__variable_97b0d3 __variable_c19f6d __variable_cf84ab __variable_4dc837 h-full\",\"suppressHydrationWarning\":true,\"children\":[[\"$\",\"head\",null,{\"children\":[\"$\",\"script\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"(function(){try{var s=localStorage.getItem(\\\"compass-theme\\\");var t=s===\\\"light\\\"||s===\\\"dark\\\"?s:(window.matchMedia(\\\"(prefers-color-scheme: dark)\\\").matches?\\\"dark\\\":\\\"light\\\");document.documentElement.dataset.theme=t}catch(e){document.documentElement.dataset.theme=\\\"light\\\"}})();\"}}]}],[\"$\",\"body\",null,{\"className\":\"font-sans h-svh overflow-hidden flex flex-col\",\"children\":[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]}]]}]]}],{\"children\":[\"/_not-found\",[\"$\",\"$1\",\"c\",{\"children\":[null,[\"$\",\"$L2\",null,{\"parallelRouterKey\":\"children\",\"error\":\"$undefined\",\"errorStyles\":\"$undefined\",\"errorScripts\":\"$undefined\",\"template\":[\"$\",\"$L3\",null,{}],\"templateStyles\":\"$undefined\",\"templateScripts\":\"$undefined\",\"notFound\":\"$undefined\",\"forbidden\":\"$undefined\",\"unauthorized\":\"$undefined\"}]]}],{\"children\":[\"__PAGE__\",[\"$\",\"$1\",\"c\",{\"children\":[[[\"$\",\"title\",null,{\"children\":\"404: This page could not be found.\"}],[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"textAlign\":\"center\",\"display\":\"flex\",\"flexDirection\":\"column\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"children\":[[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\"body{color:#000;background:#fff;margin:0}.next-error-h1{border-right:1px solid rgba(0,0,0,.3)}@media (prefers-color-scheme:dark){body{color:#fff;background:#000}.next-error-h1{border-right:1px solid rgba(255,255,255,.3)}}\"}}],[\"$\",\"h1\",null,{\"className\":\"next-error-h1\",\"style\":{\"display\":\"inline-block\",\"margin\":\"0 20px 0 0\",\"padding\":\"0 23px 0 0\",\"fontSize\":24,\"fontWeight\":500,\"verticalAlign\":\"top\",\"lineHeight\":\"49px\"},\"children\":404}],[\"$\",\"div\",null,{\"style\":{\"display\":\"inline-block\"},\"children\":[\"$\",\"h2\",null,{\"style\":{\"fontSize\":14,\"fontWeight\":400,\"lineHeight\":\"49px\",\"margin\":0},\"children\":\"This page could not be found.\"}]}]]}]}]],null,[\"$\",\"$L4\",null,{\"children\":[\"$L5\",[\"$\",\"$L6\",null,{\"promise\":\"$@7\"}]]}]]}],{},null,false]},null,false]},null,false],[\"$\",\"$1\",\"h\",{\"children\":[[\"$\",\"meta\",null,{\"name\":\"robots\",\"content\":\"noindex\"}],[[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]],[\"$\",\"$La\",null,{\"children\":[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$b\",null,{\"fallback\":null,\"children\":\"$Lc\"}]}]}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$d\",[]],\"s\":false,\"S\":true}\n"])</script><script>self.__next_f.push([1,"9:[[\"$\",\"meta\",\"0\",{\"charSet\":\"utf-8\"}],[\"$\",\"meta\",\"1\",{\"name\":\"viewport\",\"content\":\"width=device-width, initial-scale=1\"}]]\n5:null\n"])</script><script>self.__next_f.push([1,"7:{\"metadata\":[[\"$\",\"title\",\"0\",{\"children\":\"Code Compass\"}],[\"$\",\"meta\",\"1\",{\"name\":\"description\",\"content\":\"Visualize your codebase as a knowledge graph\"}]],\"error\":null,\"digest\":\"$undefined\"}\n"])</script><script>self.__next_f.push([1,"c:\"$7:metadata\"\n"])</script></body></html>