@meridiona/meridian-darwin-arm64 1.4.5 → 1.6.0

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 (58) hide show
  1. package/.env.example +24 -8
  2. package/VERSION +1 -1
  3. package/bin/meridian +0 -0
  4. package/package.json +1 -1
  5. package/services/agents/_prompts.py +21 -13
  6. package/services/agents/run_task_linker_mlx.py +10 -6
  7. package/services/pyproject.toml +1 -1
  8. package/services/skills/activity/task-classifier/SKILL.md +14 -12
  9. package/services/tests/evals/classify_session.py +122 -0
  10. package/services/tests/evals/metrics.py +34 -5
  11. package/ui/.next/BUILD_ID +1 -1
  12. package/ui/.next/build-manifest.json +3 -3
  13. package/ui/.next/prerender-manifest.json +3 -3
  14. package/ui/.next/server/app/_global-error.html +1 -1
  15. package/ui/.next/server/app/_global-error.rsc +1 -1
  16. package/ui/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  17. package/ui/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  18. package/ui/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  19. package/ui/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  20. package/ui/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  21. package/ui/.next/server/app/_not-found.html +1 -1
  22. package/ui/.next/server/app/_not-found.rsc +1 -1
  23. package/ui/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  24. package/ui/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  25. package/ui/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  26. package/ui/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  27. package/ui/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  28. package/ui/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  29. package/ui/.next/server/app/index.html +1 -1
  30. package/ui/.next/server/app/index.rsc +2 -2
  31. package/ui/.next/server/app/index.segments/__PAGE__.segment.rsc +2 -2
  32. package/ui/.next/server/app/index.segments/_full.segment.rsc +2 -2
  33. package/ui/.next/server/app/index.segments/_head.segment.rsc +1 -1
  34. package/ui/.next/server/app/index.segments/_index.segment.rsc +1 -1
  35. package/ui/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  36. package/ui/.next/server/app/page/react-loadable-manifest.json +1 -1
  37. package/ui/.next/server/app/page_client-reference-manifest.js +1 -1
  38. package/ui/.next/server/app/settings.html +1 -1
  39. package/ui/.next/server/app/settings.rsc +1 -1
  40. package/ui/.next/server/app/settings.segments/_full.segment.rsc +1 -1
  41. package/ui/.next/server/app/settings.segments/_head.segment.rsc +1 -1
  42. package/ui/.next/server/app/settings.segments/_index.segment.rsc +1 -1
  43. package/ui/.next/server/app/settings.segments/_tree.segment.rsc +1 -1
  44. package/ui/.next/server/app/settings.segments/settings/__PAGE__.segment.rsc +1 -1
  45. package/ui/.next/server/app/settings.segments/settings.segment.rsc +1 -1
  46. package/ui/.next/server/chunks/[root-of-the-server]__0yrr4w1._.js +4 -3
  47. package/ui/.next/server/middleware-build-manifest.js +3 -3
  48. package/ui/.next/server/pages/404.html +1 -1
  49. package/ui/.next/server/pages/500.html +1 -1
  50. package/ui/.next/server/server-reference-manifest.js +1 -1
  51. package/ui/.next/server/server-reference-manifest.json +1 -1
  52. package/ui/.next/static/chunks/16f557ymkx721.js +1 -0
  53. package/ui/.next/static/chunks/{0_mff2ov-3xrz.js → 17.0_3q.gw7x2.js} +1 -1
  54. package/ui/package.json +1 -1
  55. package/ui/.next/static/chunks/0h14_sgzq5gl7.js +0 -1
  56. /package/ui/.next/static/{4Kes2MbQQcEg1Xxh2Wka2 → HSR1kI5kYuEYQoBEIrPgc}/_buildManifest.js +0 -0
  57. /package/ui/.next/static/{4Kes2MbQQcEg1Xxh2Wka2 → HSR1kI5kYuEYQoBEIrPgc}/_clientMiddlewareManifest.js +0 -0
  58. /package/ui/.next/static/{4Kes2MbQQcEg1Xxh2Wka2 → HSR1kI5kYuEYQoBEIrPgc}/_ssgManifest.js +0 -0
package/.env.example CHANGED
@@ -33,15 +33,21 @@
33
33
  # JIRA_PROJECT_KEYS=KAN,ENG # optional — comma-separated; empty = all projects
34
34
 
35
35
  # ---------------------------------------------------------------------------
36
- # PM worklog (Stage 4) — Jira worklogs from classified sessions.
36
+ # PM worklog (Stage 4) — worklogs from classified sessions, for whichever
37
+ # tracker is configured above (Jira, Linear, or GitHub).
37
38
  # Runs inside the Rust daemon: one hour-driven worklog per task per hour,
38
39
  # synthesised via the MLX server's /synthesise_worklog endpoint. Requires the
39
40
  # MLX server (it hosts the synth agent).
41
+ #
42
+ # How each tracker records a worklog:
43
+ # Jira — native worklog API (time spent + comment).
44
+ # Linear — a structured comment on the issue (Linear has no time-tracking API).
45
+ # GitHub — a structured comment on the issue (GitHub has no time tracking).
40
46
  # ---------------------------------------------------------------------------
41
47
 
42
- # Nothing posts to Jira automatically. The daemon DRAFTS worklogs every hour;
43
- # you review, edit, and approve each one in the dashboard (Worklogs view), and
44
- # the daemon posts approved worklogs within ~60s. Approval is the only gate —
48
+ # Nothing posts to your tracker automatically. The daemon DRAFTS worklogs every
49
+ # hour; you review, edit, and approve each one in the dashboard (Worklogs view),
50
+ # and the daemon posts approved worklogs within ~60s. Approval is the only gate —
45
51
  # there is no auto-post switch.
46
52
 
47
53
  # Driver cadence in hours (clamped to a 60s floor). Default 1.0.
@@ -62,19 +68,29 @@
62
68
  # PM_WORKLOG_SYNTH_TIMEOUT_S=300
63
69
 
64
70
  # ---------------------------------------------------------------------------
65
- # GitHub (both required to enable the GitHub connector)
71
+ # GitHub (GITHUB_TOKEN + GITHUB_ORG required to enable the GitHub connector)
72
+ # Syncs the OPEN issues assigned to you under GITHUB_ORG; logs worklogs as
73
+ # structured issue comments (GitHub has no native time tracking).
74
+ # Token: Settings > Developer settings > Personal access tokens. A classic token
75
+ # with the `repo` scope is simplest (works for personal + org issues); a
76
+ # fine-grained token needs Issues: Read and write on the relevant repos.
77
+ # GITHUB_ORG is the issue owner — an org slug OR your own username.
66
78
  # ---------------------------------------------------------------------------
67
79
 
68
80
  # GITHUB_TOKEN=ghp_your_personal_access_token
69
81
  # GITHUB_ORG=your-org
70
- # GITHUB_REPOS=your-org/api,your-org/web # optional — comma-separated; empty = all org repos
82
+ # GITHUB_REPOS=your-org/api,your-org/web # optional — comma-separated owner/repo; empty = all repos under the owner
71
83
 
72
84
  # ---------------------------------------------------------------------------
73
- # Linear (required to enable the Linear connector)
85
+ # Linear (LINEAR_API_KEY required to enable the Linear connector)
86
+ # Syncs the issues assigned to you; logs worklogs as structured issue comments
87
+ # (Linear has no native time-tracking API).
88
+ # Key: linear.app > Settings > Account > Security & access > Personal API keys.
89
+ # Sent raw in the Authorization header (no "Bearer" prefix).
74
90
  # ---------------------------------------------------------------------------
75
91
 
76
92
  # LINEAR_API_KEY=lin_api_your_key_here
77
- # LINEAR_TEAM_IDS=TEAM1,TEAM2 # optional — comma-separated; empty = all teams
93
+ # LINEAR_TEAM_IDS=ENG,DESIGN # optional — comma-separated team KEY or id; empty = all teams
78
94
 
79
95
  # ---------------------------------------------------------------------------
80
96
  # Python LLM backend — cloud fallback for the coding-agent summariser (Claude/
package/VERSION CHANGED
@@ -1 +1 @@
1
- 1.4.5
1
+ 1.6.0
package/bin/meridian CHANGED
Binary file
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@meridiona/meridian-darwin-arm64",
3
- "version": "1.4.5",
3
+ "version": "1.6.0",
4
4
  "description": "Prebuilt Meridian app for macOS arm64 (daemon binary + dashboard + Python services). Installed via @meridiona/meridian.",
5
5
  "homepage": "https://github.com/Meridiona/meridian",
6
6
  "repository": {
@@ -11,12 +11,17 @@ _VSCODE_BANNER_RE = re.compile(
11
11
  re.IGNORECASE | re.DOTALL,
12
12
  )
13
13
 
14
- # Max chars of session_text included in the prompt. Default 2500 (~625 tokens at
15
- # 4 chars/token) enough to identify files, ticket keys, and recent activity
16
- # without inflating context in production. Override via SESSION_TEXT_CAP env var
17
- # for eval experiments; set to 0 to disable truncation entirely (caller is then
18
- # responsible for not blowing the model's context window).
19
- SESSION_TEXT_CAP = int(os.environ.get("SESSION_TEXT_CAP", "2500"))
14
+ # Max chars of session_text included in the prompt. Default 10000 (~2500 tokens
15
+ # at 4 chars/token). The old 2500 cap kept only the FIRST frames of a multi-frame
16
+ # OCR capture, so when a session spanned more than one window/app the later
17
+ # (often foreground) activity was silently dropped e.g. a session whose head
18
+ # showed an IDE but whose tail showed the user had moved to a different app/
19
+ # project got misclassified on the stale head. The classifier model has a 128K
20
+ # context window, so 2500 was far too conservative; 10000 comfortably holds a
21
+ # full multi-frame session while staying trivial for the model. Override via
22
+ # SESSION_TEXT_CAP env var; set to 0 to disable truncation entirely (caller is
23
+ # then responsible for not blowing the model's context window).
24
+ SESSION_TEXT_CAP = int(os.environ.get("SESSION_TEXT_CAP", "10000"))
20
25
 
21
26
 
22
27
  def _fmt_dur(duration_s: int | float) -> str:
@@ -51,10 +56,12 @@ def _format_session(session: dict) -> str:
51
56
  parts.append(f"time: {time_range}{dur_str}")
52
57
  elif dur is not None:
53
58
  parts.append(f"duration: {_fmt_dur(dur)}")
54
- cat = session.get("category")
55
- cat_conf = session.get("confidence")
56
- if cat:
57
- parts.append(f"category: {cat} (confidence {round(cat_conf or 0.0, 2)})")
59
+ # NOTE: the rule-based ETL category is intentionally NOT included here. It is
60
+ # a cheap heuristic derived from the SAME app/window/OCR signals the LLM
61
+ # already sees, so feeding it in only injects a correlated prior — when the
62
+ # heuristic is wrong (e.g. background-window OCR bleed), it biases the LLM
63
+ # toward the same mistake. The classifier re-derives category from the raw
64
+ # evidence and its output overwrites the rule-based value anyway.
58
65
  titles = session.get("window_titles") or []
59
66
  if titles:
60
67
  parts.append("top windows:")
@@ -116,7 +123,6 @@ def _format_recent_sessions(sessions: list[dict]) -> str:
116
123
  dur_str = _fmt_dur(s.get("duration_s") or 0)
117
124
  task_key = s.get("task_key")
118
125
  routing = s.get("task_routing") # None means unclassified
119
- category = (s.get("category") or "").strip()
120
126
  if task_key:
121
127
  target = f"→ {task_key}"
122
128
  elif routing == "untracked":
@@ -126,8 +132,10 @@ def _format_recent_sessions(sessions: list[dict]) -> str:
126
132
  target = "→ [pending]"
127
133
  else:
128
134
  target = "→ [overhead]"
129
- cat_tag = f" [{category}]" if category else ""
130
- rows.append(f" {time_str} {app:<14} {dur_str:<7} {target}{cat_tag}")
135
+ # Category is intentionally omitted recent-context is a task-continuity
136
+ # signal only; carrying the (rule-based or prior-LLM) category tag would
137
+ # feed a category prior back into classification.
138
+ rows.append(f" {time_str} {app:<14} {dur_str:<7} {target}")
131
139
  return "\n".join(rows)
132
140
 
133
141
 
@@ -83,10 +83,10 @@ class SessionClassification(BaseModel):
83
83
  ] = Field(
84
84
  ...,
85
85
  description=(
86
- "The single best activity category for this session. A rule-based "
87
- "guess is supplied in the input confirm it or correct it from the "
88
- "evidence. Declared early in the schema so FSM decoding always emits "
89
- "it before the long session_summary field."
86
+ "The single best activity category for this session. Derive it from "
87
+ "the evidence (app, window titles, screen content); no category is "
88
+ "supplied in the input. Declared early in the schema so FSM decoding "
89
+ "always emits it before the long session_summary field."
90
90
  ),
91
91
  )
92
92
  category_confidence: float = Field(
@@ -232,9 +232,13 @@ def _fetch_session(
232
232
  def _fetch_recent_sessions(
233
233
  con: _sqlite3.Connection, before_id: int
234
234
  ) -> list[dict[str, Any]]:
235
+ # Recent context is a task-continuity signal only: app, time, duration and
236
+ # which ticket each recent session mapped to. We deliberately do NOT select
237
+ # session_text/excerpt or category — recent OCR is noise here and a category
238
+ # tag would feed a prior back into classification. (session_text is still
239
+ # referenced in WHERE only to skip empty-capture rows.)
235
240
  rows = con.execute(
236
- "SELECT app_name, started_at, duration_s, task_key, task_routing, category,"
237
- " COALESCE(SUBSTR(session_text, 1, 200), '') AS text_excerpt"
241
+ "SELECT app_name, started_at, duration_s, task_key, task_routing"
238
242
  " FROM app_sessions"
239
243
  " WHERE id < ? AND duration_s > 1 AND COALESCE(session_text,'') != ''"
240
244
  " ORDER BY id DESC LIMIT ?",
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "meridian-agents"
7
- version = "1.4.5"
7
+ version = "1.6.0"
8
8
  description = "Meridian agents — hermes task linking and Jira progress updates for meridian.db"
9
9
  requires-python = ">=3.11"
10
10
  authors = [{ name = "Meridiona" }]
@@ -24,7 +24,7 @@ The task classifier sits at the center of Meridian's workflow understanding:
24
24
 
25
25
  ## Classification Decision Tree
26
26
 
27
- For each session, you must decide:
27
+ For each session, decide in this order. **Core principle: do NOT try to fit every session to an existing ticket. Assign a `task_key` only when the session's OWN evidence clearly matches that specific ticket's scope. Most real work that isn't an obvious match is `untracked`, not a forced link.**
28
28
 
29
29
  ### 1. Is this overhead?
30
30
  If the session is **idle, music, system settings,or clearly personal/unrelated activity** → return:
@@ -33,27 +33,29 @@ If the session is **idle, music, system settings,or clearly personal/unrelated a
33
33
  ```
34
34
  **overhead is a hard discard.** These sessions are thrown away — never surfaced, never used for inference, never create tasks. When in doubt between overhead and untracked, ask: *"Would a manager care that this happened?"* If no, it's overhead.
35
35
 
36
- ### 2. Is this work-related?
37
- If the session shows **any real work signal** (coding, research, meetings, writing, debugging, reviewing, learning) but **no Jira candidate matches** → mark as **untracked** and return:
36
+ ### 2. Is this real work that ISN'T clearly one of the candidate tickets? → untracked
37
+ If the session shows **any real work signal** (coding, research, meetings, writing, debugging, reviewing, learning) but it does **not clearly match the scope of a candidate ticket** → mark as **untracked**:
38
38
  ```json
39
39
  {"task_key": null, "confidence": 0.6-0.8, "session_type": "untracked", "routing": "queue"}
40
40
  ```
41
- **untracked sessions are kept and used downstream** for workload analysis, capacity reporting, and automatic new-task creation. Mark dimensions to capture *what* the work was. Examples that must be `untracked` (not `overhead`): standups, retros, code reviews on untracked PRs, config/infra housekeeping, general repo exploration, internal tool usage.
41
+ **This is the important, common case — and it is what `untracked` MEANS: the user genuinely did this work, but there is no Jira ticket for it yet.** Downstream, Meridian uses untracked sessions to **create or update** the matching Jira task. So it is critical that you do **not** shoehorn this work into an unrelated existing ticket just because it is the only candidate available, or because recent sessions were on it. **A wrong task link is worse than `untracked`** it pollutes a real ticket's worklog and hides the genuine untracked work that should have spawned its own ticket. When the evidence doesn't clearly fit a candidate, choose `untracked`.
42
42
 
43
- ### 3. Can it map to an open Jira ticket?
44
- If the session evidence **directly or contextually matches** an open ticket → return:
43
+ `untracked` sessions are kept and used downstream (workload analysis, capacity reporting, new-task creation). Mark dimensions to capture *what* the work was. Examples that must be `untracked` (not `overhead`): standups, retros, code reviews on untracked PRs, config/infra housekeeping, general repo exploration, general research, **and any work on a feature/bug/chore that has no matching candidate ticket**.
44
+
45
+ ### 3. Does it CLEARLY map to one specific candidate ticket? → task
46
+ Assign a `task_key` **only** when the session's own evidence (window titles, OCR, file/branch names, an explicit ticket-key mention) directly matches the **scope described in that ticket's title/description** → return:
45
47
  ```json
46
48
  {"task_key": "KEY-123", "confidence": 0.50-0.90, "session_type": "task", "routing": "auto"}
47
49
  ```
48
- Cite the evidence (window title, OCR snippet, context from previous sessions) and infer activity dimensions.
50
+ Recent-session continuity may *support* a match, but **continuity alone is never enough** — the current session must carry its own evidence that fits the ticket. If the active app/window shows the user is now on something else (a different project, a meeting, another repo, a doc for another team), classify by **that**, not by what they were doing minutes ago. Cite the specific evidence, and infer activity dimensions.
49
51
 
50
52
  ## Your inputs
51
53
 
52
54
  The user message contains:
53
55
 
54
- - **SESSION** — app, category (with confidence), duration, top window titles, and counts of OCR/audio captures.
56
+ - **SESSION** — app, duration, top window titles, and the screen content (OCR / a11y). Decide the category yourself from this evidence; no category is provided.
55
57
  - **CANDIDATE TICKETS** — all open Jira tickets. These are the only tickets you may choose from.
56
- - **RECENT SESSIONS** (previous 5) — context to help disambiguate. Example: *"User was on KAN-42 (coding) 5 minutes ago, then Slack, now back in VS Code."* likely same task, even if Slack doesn't directly match KAN-42.
58
+ - **RECENT SESSIONS** (previous 5) — app / time / duration / which ticket each mapped to (no screen text). A **weak disambiguation hint only**: it can support a match when the current session ALSO has matching evidence, but it must never override what the current session itself shows. Recent activity on a ticket does not make the current session that ticket.
57
59
 
58
60
  ## Available capabilities
59
61
 
@@ -98,7 +100,7 @@ Reply with ONE valid JSON object — no preamble, no markdown fences, no follow-
98
100
  ### Field rules
99
101
  - `task_key` — must be one of the supplied candidates, or `null`. Never invent a key.
100
102
  - `confidence` — see Scoring heuristics section for exact ranges per outcome type.
101
- - `category` — the single best activity category (see taxonomy below). The input carries a rule-based guess; confirm it or correct it from the evidence.
103
+ - `category` — the single best activity category (see taxonomy below). Derive it yourself from the evidence (app, window titles, screen content); no category is provided in the input.
102
104
  - `category_confidence` — how certain you are about `category`, `0.0`–`1.0`.
103
105
  - `category_explanation` — ONE concise sentence justifying the category, citing the app / window titles / OCR evidence. Shown in the dashboard next to the category.
104
106
  - `session_type` — `"task"` links to Jira; `"overhead"` is thrown away; `"untracked"` is kept for workload analysis.
@@ -199,7 +201,7 @@ You have access to **the previous 5 sessions** to disambiguate the current sessi
199
201
  - Session 2 (3 min ago): Slack, discussing PR review for KAN-42 → **if related to same work**, task_key: KAN-42, confidence: 0.75 (work mention + prior context)
200
202
  - Session 3 (now): VS Code, editing same file → task_key: KAN-42, confidence: 0.85 (context continuity)
201
203
 
202
- **Decision:** If Session 2 (Slack) content shows it's about the same work (discussing the work or searching about it), classify it to **KAN-42** using context from Session 1. If Slack is generic work discussion with no connection to the prior task, return `null` with `session_type: "untracked"`.
204
+ **Decision:** Only link Session 2 to KAN-42 if Session 2's **own content** shows it is about that work (the OCR/window discusses or searches the KAN-42 work). If Session 2 is generic, OR shows the user has moved to *different* work (another project, another team's doc, an unrelated meeting), return `null` with `session_type: "untracked"` (or a different ticket if its own evidence matches one) — **do not inherit KAN-42 just because it was the recent task.** Continuity is a tie-breaker between plausible matches, never a substitute for current-session evidence.
203
205
 
204
206
  Example reasoning for Session 2 (if task-related): `"Slack discusses PR review for KAN-42 implementation mentioned in prior VS Code session; linked via work context."`
205
207
 
@@ -208,7 +210,7 @@ Example reasoning for Session 2 (if task-related): `"Slack discusses PR review f
208
210
  **When task_key is not null (matched to a ticket):**
209
211
  - **Task key + work alignment** — `confidence ≥ 0.90`, `session_type: "task"`
210
212
  - **Work description alignment** — `0.75–0.85`, `session_type: "task"`
211
- - **Context continuity** — `0.75–0.85`, `session_type: "task"`
213
+ - **Context continuity (current session ALSO has matching evidence)** — `0.75–0.85`, `session_type: "task"`. Continuity with no current-session evidence is **not** a task — use `untracked`.
212
214
  - **Generic project-level match** — `0.50–0.65`, `session_type: "task"`
213
215
  - **Task key only** — `0.60–0.75`, `session_type: "task"` (lower than key+alignment because work intent unclear)
214
216
 
@@ -0,0 +1,122 @@
1
+ """Dry-run the task classifier for one or more session ids — read-only.
2
+
3
+ Drives the SAME code path the daemon uses: POSTs the session id(s) to the
4
+ running MLX server's /classify_sessions endpoint, which runs `_classify_one`
5
+ (fetch session + recent context + pm_tasks → build prompt → model → parse).
6
+ The Python endpoint only RETURNS the result; the DB write is done separately by
7
+ the Rust daemon, so calling this never mutates app_sessions — you see exactly
8
+ what the classifier WOULD output right now, with the current code and prompt.
9
+
10
+ Usage:
11
+ services/.venv/bin/python services/tests/evals/classify_session.py 20128
12
+ services/.venv/bin/python services/tests/evals/classify_session.py 20128 20127 --show-prompt
13
+ MLX_SERVER_URL=http://127.0.0.1:7823 ... classify_session.py 20128
14
+
15
+ The MLX server must be running (meridian status / port 7823). It uses the
16
+ already-loaded model, so this is fast — no in-process model load.
17
+ """
18
+
19
+ from __future__ import annotations
20
+
21
+ import argparse
22
+ import json
23
+ import os
24
+ import sqlite3
25
+ import sys
26
+ import urllib.request
27
+ from pathlib import Path
28
+
29
+ _DEFAULT_URL = os.environ.get("MLX_SERVER_URL", "http://127.0.0.1:7823").rstrip("/")
30
+ _DEFAULT_DB = os.path.expanduser(
31
+ os.environ.get("MERIDIAN_DB", "~/.meridian/meridian.db")
32
+ )
33
+
34
+
35
+ def _reconstruct_prompt(db_path: str, session_id: int) -> str | None:
36
+ """Rebuild the exact prompt via the production builder (read-only)."""
37
+ # Import lazily so the common path (no --show-prompt) needs no agents deps.
38
+ sys.path.insert(0, str(Path(__file__).resolve().parents[2])) # services/
39
+ from agents._prompts import build_user_message
40
+ from agents.run_task_linker_mlx import (
41
+ _fetch_pm_tasks,
42
+ _fetch_recent_sessions,
43
+ _fetch_session,
44
+ )
45
+
46
+ con = sqlite3.connect(f"file:{db_path}?mode=ro", uri=True)
47
+ con.row_factory = sqlite3.Row
48
+ raw = _fetch_session(con, session_id)
49
+ if raw is None:
50
+ return None
51
+ recent = _fetch_recent_sessions(con, session_id)
52
+ pm_tasks = _fetch_pm_tasks(con)
53
+ session_text = raw.get("session_text") or ""
54
+ if raw.get("claude_session_uuid") and (raw.get("session_summary") or "").strip():
55
+ session_text = raw["session_summary"]
56
+ session = {
57
+ "id": session_id,
58
+ "app_name": raw.get("app_name"),
59
+ "started_at": raw.get("started_at", ""),
60
+ "ended_at": raw.get("ended_at", ""),
61
+ "duration_s": raw.get("duration_s"),
62
+ "session_text": session_text,
63
+ "session_text_source": raw.get("session_text_source", "unknown"),
64
+ "window_titles": json.loads(raw.get("window_titles") or "[]"),
65
+ "category": raw.get("category"),
66
+ "confidence": raw.get("confidence", 0.0),
67
+ "audio_snippets": [],
68
+ }
69
+ return build_user_message(session, pm_tasks, recent_sessions=recent)
70
+
71
+
72
+ def _classify(url: str, db_path: str, session_ids: list[int]) -> list[dict]:
73
+ payload = json.dumps({"session_ids": session_ids, "meridian_db": db_path}).encode()
74
+ req = urllib.request.Request(
75
+ f"{url}/classify_sessions",
76
+ data=payload,
77
+ headers={"Content-Type": "application/json"},
78
+ )
79
+ with urllib.request.urlopen(req, timeout=600) as resp:
80
+ return json.loads(resp.read()).get("results", [])
81
+
82
+
83
+ def main() -> int:
84
+ ap = argparse.ArgumentParser(description=__doc__)
85
+ ap.add_argument("session_ids", nargs="+", type=int, help="session id(s) to classify")
86
+ ap.add_argument("--show-prompt", action="store_true", help="also print the exact prompt sent")
87
+ ap.add_argument("--url", default=_DEFAULT_URL, help=f"MLX server (default {_DEFAULT_URL})")
88
+ ap.add_argument("--db", default=_DEFAULT_DB, help=f"meridian.db (default {_DEFAULT_DB})")
89
+ ap.add_argument("--json", action="store_true", help="print raw JSON results")
90
+ args = ap.parse_args()
91
+
92
+ if args.show_prompt:
93
+ for sid in args.session_ids:
94
+ prompt = _reconstruct_prompt(args.db, sid)
95
+ print(f"\n{'='*30} PROMPT for session {sid} {'='*30}")
96
+ print(prompt if prompt is not None else f"(session {sid} not found)")
97
+
98
+ results = _classify(args.url, args.db, args.session_ids)
99
+
100
+ if args.json:
101
+ print(json.dumps(results, indent=2))
102
+ return 0
103
+
104
+ for r in results:
105
+ print(f"\n{'='*30} RESULT for session {r.get('session_id')} {'='*30}")
106
+ for k in (
107
+ "task_key",
108
+ "session_type",
109
+ "confidence",
110
+ "category",
111
+ "category_confidence",
112
+ "method",
113
+ ):
114
+ print(f" {k:20} = {r.get(k)}")
115
+ reasoning = (r.get("reasoning") or "").strip()
116
+ if reasoning:
117
+ print(f" reasoning = {reasoning}")
118
+ return 0
119
+
120
+
121
+ if __name__ == "__main__":
122
+ raise SystemExit(main())
@@ -23,7 +23,6 @@ from pathlib import Path
23
23
  import sys
24
24
 
25
25
  from deepeval.metrics import BaseMetric, TaskCompletionMetric
26
- from deepeval.models import OllamaModel
27
26
  from deepeval.test_case import LLMTestCase
28
27
 
29
28
  _SERVICES_DIR = Path(__file__).parent.parent.parent
@@ -33,7 +32,33 @@ if str(_SERVICES_DIR) not in sys.path:
33
32
  _MODEL = os.environ.get("OLLAMA_MODEL", "gemma4:31b")
34
33
  _HOST = os.environ.get("OLLAMA_HOST", "http://localhost:11434")
35
34
 
36
- _judge = OllamaModel(model=_MODEL, base_url=_HOST)
35
+
36
+ def _make_judge() -> "object | None":
37
+ """Build the LLM judge — ONLY the agent-e2e TaskCompletionMetric needs it.
38
+
39
+ The classifier metrics below (TaskKeyMatch / SessionTypeMatch) are pure
40
+ exact-match and require no judge. Importing this module must therefore NOT
41
+ hard-depend on Ollama: if the `ollama` package or server is unavailable we
42
+ return None and the classifier eval runs unaffected. Construction is inside
43
+ the function (not at import) because OllamaModel() pulls in `ollama` only
44
+ when instantiated.
45
+ """
46
+ try:
47
+ from deepeval.models import OllamaModel
48
+
49
+ return OllamaModel(model=_MODEL, base_url=_HOST)
50
+ except Exception as exc: # noqa: BLE001 — missing pkg, server down, etc.
51
+ import warnings
52
+
53
+ warnings.warn(
54
+ f"LLM judge unavailable ({exc}); agent-e2e metrics disabled. "
55
+ "Classifier exact-match metrics are unaffected.",
56
+ stacklevel=2,
57
+ )
58
+ return None
59
+
60
+
61
+ _judge = _make_judge()
37
62
 
38
63
  _NULL_LITERALS = {"none", "null", "n/a", "nil", "undefined", ""}
39
64
 
@@ -146,9 +171,13 @@ class SessionTypeMatchMetric(BaseMetric):
146
171
  # Metric lists — import these in eval files
147
172
  # ---------------------------------------------------------------------------
148
173
 
149
- AGENT_E2E_METRICS = [
150
- TaskCompletionMetric(threshold=0.5, model=_judge, include_reason=True),
151
- ]
174
+ # Only built when a judge is available — otherwise empty so importing this module
175
+ # (e.g. for the classifier eval) never requires Ollama.
176
+ AGENT_E2E_METRICS = (
177
+ [TaskCompletionMetric(threshold=0.5, model=_judge, include_reason=True)]
178
+ if _judge is not None
179
+ else []
180
+ )
152
181
 
153
182
  CLASSIFIER_METRICS = [
154
183
  TaskKeyMatchMetric(threshold=1.0),
package/ui/.next/BUILD_ID CHANGED
@@ -1 +1 @@
1
- 4Kes2MbQQcEg1Xxh2Wka2
1
+ HSR1kI5kYuEYQoBEIrPgc
@@ -7,9 +7,9 @@
7
7
  "static/chunks/03~yq9q893hmn.js"
8
8
  ],
9
9
  "lowPriorityFiles": [
10
- "static/4Kes2MbQQcEg1Xxh2Wka2/_buildManifest.js",
11
- "static/4Kes2MbQQcEg1Xxh2Wka2/_ssgManifest.js",
12
- "static/4Kes2MbQQcEg1Xxh2Wka2/_clientMiddlewareManifest.js"
10
+ "static/HSR1kI5kYuEYQoBEIrPgc/_buildManifest.js",
11
+ "static/HSR1kI5kYuEYQoBEIrPgc/_ssgManifest.js",
12
+ "static/HSR1kI5kYuEYQoBEIrPgc/_clientMiddlewareManifest.js"
13
13
  ],
14
14
  "rootMainFiles": [
15
15
  "static/chunks/120gq8w9i9o8g.js",
@@ -102,8 +102,8 @@
102
102
  "dynamicRoutes": {},
103
103
  "notFoundRoutes": [],
104
104
  "preview": {
105
- "previewModeId": "fc534b603f7115738018a819ba72f9e0",
106
- "previewModeSigningKey": "4e561e422ef4f00cc92e3d37f5bb1048ac2e20f4630e7a0b164b42d18f227b70",
107
- "previewModeEncryptionKey": "2009dd4f582129353bb90d0882edaff54ec6d73d1741e30f9c0f013f4075364b"
105
+ "previewModeId": "5f7a3850682c84e2757e7ca539ddc5a1",
106
+ "previewModeSigningKey": "d5c9fffc27c32dee509ee94a8a572e4e725eb91fe3ee2974879915e2e129d0d4",
107
+ "previewModeEncryptionKey": "5732f49d3782565713514da6e106a37714e2b6b9c631bb155f09cd13cc87a3ad"
108
108
  }
109
109
  }
@@ -1 +1 @@
1
- <!DOCTYPE html><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/120gq8w9i9o8g.js"/><script src="/_next/static/chunks/140ovxvjat1ch.js" async=""></script><script src="/_next/static/chunks/0chwa38d3r7hi.js" async=""></script><script src="/_next/static/chunks/turbopack-0-ynxavni4q39.js" async=""></script><script src="/_next/static/chunks/0dbhjjzl8qfwv.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: This page couldn’t load</title><style>:root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }</style><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body><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;display:flex;align-items:center;justify-content:center"><div style="margin-top:-32px;max-width:325px;padding:32px 28px;text-align:left"><svg width="32" height="32" viewBox="-0.2 -1.5 32 32" fill="none" style="margin-bottom:24px"><path d="M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z" fill="var(--next-error-title)"></path></svg><h1 style="font-size:24px;font-weight:500;letter-spacing:-0.02em;line-height:32px;margin:0 0 12px 0;color:var(--next-error-title)">This page couldn’t load</h1><p style="font-size:14px;font-weight:400;line-height:21px;margin:0 0 20px 0;color:var(--next-error-message)">A server error occurred. Reload to try again.</p><form style="margin:0"><button type="submit" style="display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;font-size:14px;font-weight:500;line-height:20px;border-radius:6px;cursor:pointer;color:var(--next-error-btn-text);background:var(--next-error-btn-bg);border:var(--next-error-btn-border)">Reload</button></form></div></div><!--$--><!--/$--><script src="/_next/static/chunks/120gq8w9i9o8g.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[39756,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"default\"]\n4:I[97367,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n8:I[97367,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"ViewportBoundary\"]\na:I[97367,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"MetadataBoundary\"]\nc:I[68027,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"default\",1]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]}],[[\"$\",\"$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\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[[\"$\",\"title\",null,{\"children\":\"500: This page couldn’t load\"}],[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }\"}}]]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"display\":\"flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"marginTop\":\"-32px\",\"maxWidth\":\"325px\",\"padding\":\"32px 28px\",\"textAlign\":\"left\"},\"children\":[[\"$\",\"svg\",null,{\"width\":\"32\",\"height\":\"32\",\"viewBox\":\"-0.2 -1.5 32 32\",\"fill\":\"none\",\"style\":{\"marginBottom\":\"24px\"},\"children\":[\"$\",\"path\",null,{\"d\":\"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z\",\"fill\":\"var(--next-error-title)\"}]}],[\"$\",\"h1\",null,{\"style\":{\"fontSize\":\"24px\",\"fontWeight\":500,\"letterSpacing\":\"-0.02em\",\"lineHeight\":\"32px\",\"margin\":\"0 0 12px 0\",\"color\":\"var(--next-error-title)\"},\"children\":\"This page couldn’t load\"}],[\"$\",\"p\",null,{\"style\":{\"fontSize\":\"14px\",\"fontWeight\":400,\"lineHeight\":\"21px\",\"margin\":\"0 0 20px 0\",\"color\":\"var(--next-error-message)\"},\"children\":\"A server error occurred. Reload to try again.\"}],[\"$\",\"form\",null,{\"style\":{\"margin\":0},\"children\":[\"$\",\"button\",null,{\"type\":\"submit\",\"style\":{\"display\":\"inline-flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\",\"height\":\"32px\",\"padding\":\"0 12px\",\"fontSize\":\"14px\",\"fontWeight\":500,\"lineHeight\":\"20px\",\"borderRadius\":\"6px\",\"cursor\":\"pointer\",\"color\":\"var(--next-error-btn-text)\",\"background\":\"var(--next-error-btn-bg)\",\"border\":\"var(--next-error-btn-border)\"},\"children\":\"Reload\"}]}]]}]}]}]]}],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$@7\"],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"4Kes2MbQQcEg1Xxh2Wka2\"}\n"])</script><script>self.__next_f.push([1,"d:[]\n7:\"$Wd\"\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\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\nb:[]\n"])</script></body></html>
1
+ <!DOCTYPE html><html id="__next_error__"><head><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1"/><link rel="preload" as="script" fetchPriority="low" href="/_next/static/chunks/120gq8w9i9o8g.js"/><script src="/_next/static/chunks/140ovxvjat1ch.js" async=""></script><script src="/_next/static/chunks/0chwa38d3r7hi.js" async=""></script><script src="/_next/static/chunks/turbopack-0-ynxavni4q39.js" async=""></script><script src="/_next/static/chunks/0dbhjjzl8qfwv.js" async=""></script><meta name="next-size-adjust" content=""/><title>500: This page couldn’t load</title><style>:root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }</style><script src="/_next/static/chunks/03~yq9q893hmn.js" noModule=""></script></head><body><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;display:flex;align-items:center;justify-content:center"><div style="margin-top:-32px;max-width:325px;padding:32px 28px;text-align:left"><svg width="32" height="32" viewBox="-0.2 -1.5 32 32" fill="none" style="margin-bottom:24px"><path d="M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z" fill="var(--next-error-title)"></path></svg><h1 style="font-size:24px;font-weight:500;letter-spacing:-0.02em;line-height:32px;margin:0 0 12px 0;color:var(--next-error-title)">This page couldn’t load</h1><p style="font-size:14px;font-weight:400;line-height:21px;margin:0 0 20px 0;color:var(--next-error-message)">A server error occurred. Reload to try again.</p><form style="margin:0"><button type="submit" style="display:inline-flex;align-items:center;justify-content:center;height:32px;padding:0 12px;font-size:14px;font-weight:500;line-height:20px;border-radius:6px;cursor:pointer;color:var(--next-error-btn-text);background:var(--next-error-btn-bg);border:var(--next-error-btn-border)">Reload</button></form></div></div><!--$--><!--/$--><script src="/_next/static/chunks/120gq8w9i9o8g.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[39756,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"default\"]\n3:I[37457,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"default\"]\n4:I[97367,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"OutletBoundary\"]\n5:\"$Sreact.suspense\"\n8:I[97367,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"ViewportBoundary\"]\na:I[97367,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"MetadataBoundary\"]\nc:I[68027,[\"/_next/static/chunks/0dbhjjzl8qfwv.js\"],\"default\",1]\n"])</script><script>self.__next_f.push([1,"0:{\"P\":null,\"c\":[\"\",\"_global-error\"],\"q\":\"\",\"i\":false,\"f\":[[[\"\",{\"children\":[\"__PAGE__\",{}]}],[[\"$\",\"$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\":[[\"$\",\"$1\",\"c\",{\"children\":[[\"$\",\"html\",null,{\"id\":\"__next_error__\",\"children\":[[\"$\",\"head\",null,{\"children\":[[\"$\",\"title\",null,{\"children\":\"500: This page couldn’t load\"}],[\"$\",\"style\",null,{\"dangerouslySetInnerHTML\":{\"__html\":\":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }\"}}]]}],[\"$\",\"body\",null,{\"children\":[\"$\",\"div\",null,{\"style\":{\"fontFamily\":\"system-ui,\\\"Segoe UI\\\",Roboto,Helvetica,Arial,sans-serif,\\\"Apple Color Emoji\\\",\\\"Segoe UI Emoji\\\"\",\"height\":\"100vh\",\"display\":\"flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\"},\"children\":[\"$\",\"div\",null,{\"style\":{\"marginTop\":\"-32px\",\"maxWidth\":\"325px\",\"padding\":\"32px 28px\",\"textAlign\":\"left\"},\"children\":[[\"$\",\"svg\",null,{\"width\":\"32\",\"height\":\"32\",\"viewBox\":\"-0.2 -1.5 32 32\",\"fill\":\"none\",\"style\":{\"marginBottom\":\"24px\"},\"children\":[\"$\",\"path\",null,{\"d\":\"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z\",\"fill\":\"var(--next-error-title)\"}]}],[\"$\",\"h1\",null,{\"style\":{\"fontSize\":\"24px\",\"fontWeight\":500,\"letterSpacing\":\"-0.02em\",\"lineHeight\":\"32px\",\"margin\":\"0 0 12px 0\",\"color\":\"var(--next-error-title)\"},\"children\":\"This page couldn’t load\"}],[\"$\",\"p\",null,{\"style\":{\"fontSize\":\"14px\",\"fontWeight\":400,\"lineHeight\":\"21px\",\"margin\":\"0 0 20px 0\",\"color\":\"var(--next-error-message)\"},\"children\":\"A server error occurred. Reload to try again.\"}],[\"$\",\"form\",null,{\"style\":{\"margin\":0},\"children\":[\"$\",\"button\",null,{\"type\":\"submit\",\"style\":{\"display\":\"inline-flex\",\"alignItems\":\"center\",\"justifyContent\":\"center\",\"height\":\"32px\",\"padding\":\"0 12px\",\"fontSize\":\"14px\",\"fontWeight\":500,\"lineHeight\":\"20px\",\"borderRadius\":\"6px\",\"cursor\":\"pointer\",\"color\":\"var(--next-error-btn-text)\",\"background\":\"var(--next-error-btn-bg)\",\"border\":\"var(--next-error-btn-border)\"},\"children\":\"Reload\"}]}]]}]}]}]]}],null,[\"$\",\"$L4\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.MetadataOutlet\",\"children\":\"$@6\"}]}]]}],{},null,false,null]},null,false,\"$@7\"],[\"$\",\"$1\",\"h\",{\"children\":[null,[\"$\",\"$L8\",null,{\"children\":\"$L9\"}],[\"$\",\"div\",null,{\"hidden\":true,\"children\":[\"$\",\"$La\",null,{\"children\":[\"$\",\"$5\",null,{\"name\":\"Next.Metadata\",\"children\":\"$Lb\"}]}]}],[\"$\",\"meta\",null,{\"name\":\"next-size-adjust\",\"content\":\"\"}]]}],false]],\"m\":\"$undefined\",\"G\":[\"$c\",[]],\"S\":true,\"h\":null,\"s\":\"$undefined\",\"l\":\"$undefined\",\"p\":\"$undefined\",\"d\":\"$undefined\",\"b\":\"HSR1kI5kYuEYQoBEIrPgc\"}\n"])</script><script>self.__next_f.push([1,"d:[]\n7:\"$Wd\"\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\"}]]\n"])</script><script>self.__next_f.push([1,"6:null\nb:[]\n"])</script></body></html>
@@ -6,7 +6,7 @@
6
6
  8:I[97367,["/_next/static/chunks/0dbhjjzl8qfwv.js"],"ViewportBoundary"]
7
7
  a:I[97367,["/_next/static/chunks/0dbhjjzl8qfwv.js"],"MetadataBoundary"]
8
8
  c:I[68027,["/_next/static/chunks/0dbhjjzl8qfwv.js"],"default",1]
9
- 0:{"P":null,"c":["","_global-error"],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]}],[["$","$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":[["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":[["$","title",null,{"children":"500: This page couldn’t load"}],["$","style",null,{"dangerouslySetInnerHTML":{"__html":":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }"}}]]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","display":"flex","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"marginTop":"-32px","maxWidth":"325px","padding":"32px 28px","textAlign":"left"},"children":[["$","svg",null,{"width":"32","height":"32","viewBox":"-0.2 -1.5 32 32","fill":"none","style":{"marginBottom":"24px"},"children":["$","path",null,{"d":"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z","fill":"var(--next-error-title)"}]}],["$","h1",null,{"style":{"fontSize":"24px","fontWeight":500,"letterSpacing":"-0.02em","lineHeight":"32px","margin":"0 0 12px 0","color":"var(--next-error-title)"},"children":"This page couldn’t load"}],["$","p",null,{"style":{"fontSize":"14px","fontWeight":400,"lineHeight":"21px","margin":"0 0 20px 0","color":"var(--next-error-message)"},"children":"A server error occurred. Reload to try again."}],["$","form",null,{"style":{"margin":0},"children":["$","button",null,{"type":"submit","style":{"display":"inline-flex","alignItems":"center","justifyContent":"center","height":"32px","padding":"0 12px","fontSize":"14px","fontWeight":500,"lineHeight":"20px","borderRadius":"6px","cursor":"pointer","color":"var(--next-error-btn-text)","background":"var(--next-error-btn-bg)","border":"var(--next-error-btn-border)"},"children":"Reload"}]}]]}]}]}]]}],null,["$","$L4",null,{"children":["$","$5",null,{"name":"Next.MetadataOutlet","children":"$@6"}]}]]}],{},null,false,null]},null,false,"$@7"],["$","$1","h",{"children":[null,["$","$L8",null,{"children":"$L9"}],["$","div",null,{"hidden":true,"children":["$","$La",null,{"children":["$","$5",null,{"name":"Next.Metadata","children":"$Lb"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$c",[]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"4Kes2MbQQcEg1Xxh2Wka2"}
9
+ 0:{"P":null,"c":["","_global-error"],"q":"","i":false,"f":[[["",{"children":["__PAGE__",{}]}],[["$","$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":[["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":[["$","title",null,{"children":"500: This page couldn’t load"}],["$","style",null,{"dangerouslySetInnerHTML":{"__html":":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }"}}]]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","display":"flex","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"marginTop":"-32px","maxWidth":"325px","padding":"32px 28px","textAlign":"left"},"children":[["$","svg",null,{"width":"32","height":"32","viewBox":"-0.2 -1.5 32 32","fill":"none","style":{"marginBottom":"24px"},"children":["$","path",null,{"d":"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z","fill":"var(--next-error-title)"}]}],["$","h1",null,{"style":{"fontSize":"24px","fontWeight":500,"letterSpacing":"-0.02em","lineHeight":"32px","margin":"0 0 12px 0","color":"var(--next-error-title)"},"children":"This page couldn’t load"}],["$","p",null,{"style":{"fontSize":"14px","fontWeight":400,"lineHeight":"21px","margin":"0 0 20px 0","color":"var(--next-error-message)"},"children":"A server error occurred. Reload to try again."}],["$","form",null,{"style":{"margin":0},"children":["$","button",null,{"type":"submit","style":{"display":"inline-flex","alignItems":"center","justifyContent":"center","height":"32px","padding":"0 12px","fontSize":"14px","fontWeight":500,"lineHeight":"20px","borderRadius":"6px","cursor":"pointer","color":"var(--next-error-btn-text)","background":"var(--next-error-btn-bg)","border":"var(--next-error-btn-border)"},"children":"Reload"}]}]]}]}]}]]}],null,["$","$L4",null,{"children":["$","$5",null,{"name":"Next.MetadataOutlet","children":"$@6"}]}]]}],{},null,false,null]},null,false,"$@7"],["$","$1","h",{"children":[null,["$","$L8",null,{"children":"$L9"}],["$","div",null,{"hidden":true,"children":["$","$La",null,{"children":["$","$5",null,{"name":"Next.Metadata","children":"$Lb"}]}]}],["$","meta",null,{"name":"next-size-adjust","content":""}]]}],false]],"m":"$undefined","G":["$c",[]],"S":true,"h":null,"s":"$undefined","l":"$undefined","p":"$undefined","d":"$undefined","b":"HSR1kI5kYuEYQoBEIrPgc"}
10
10
  d:[]
11
11
  7:"$Wd"
12
12
  9:[["$","meta","0",{"charSet":"utf-8"}],["$","meta","1",{"name":"viewport","content":"width=device-width, initial-scale=1"}]]
@@ -1,5 +1,5 @@
1
1
  1:"$Sreact.fragment"
2
2
  2:I[97367,["/_next/static/chunks/0dbhjjzl8qfwv.js"],"OutletBoundary"]
3
3
  3:"$Sreact.suspense"
4
- 0:{"rsc":["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":[["$","title",null,{"children":"500: This page couldn’t load"}],["$","style",null,{"dangerouslySetInnerHTML":{"__html":":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }"}}]]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","display":"flex","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"marginTop":"-32px","maxWidth":"325px","padding":"32px 28px","textAlign":"left"},"children":[["$","svg",null,{"width":"32","height":"32","viewBox":"-0.2 -1.5 32 32","fill":"none","style":{"marginBottom":"24px"},"children":["$","path",null,{"d":"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z","fill":"var(--next-error-title)"}]}],["$","h1",null,{"style":{"fontSize":"24px","fontWeight":500,"letterSpacing":"-0.02em","lineHeight":"32px","margin":"0 0 12px 0","color":"var(--next-error-title)"},"children":"This page couldn’t load"}],["$","p",null,{"style":{"fontSize":"14px","fontWeight":400,"lineHeight":"21px","margin":"0 0 20px 0","color":"var(--next-error-message)"},"children":"A server error occurred. Reload to try again."}],["$","form",null,{"style":{"margin":0},"children":["$","button",null,{"type":"submit","style":{"display":"inline-flex","alignItems":"center","justifyContent":"center","height":"32px","padding":"0 12px","fontSize":"14px","fontWeight":500,"lineHeight":"20px","borderRadius":"6px","cursor":"pointer","color":"var(--next-error-btn-text)","background":"var(--next-error-btn-bg)","border":"var(--next-error-btn-border)"},"children":"Reload"}]}]]}]}]}]]}],null,["$","$L2",null,{"children":["$","$3",null,{"name":"Next.MetadataOutlet","children":"$@4"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"4Kes2MbQQcEg1Xxh2Wka2"}
4
+ 0:{"rsc":["$","$1","c",{"children":[["$","html",null,{"id":"__next_error__","children":[["$","head",null,{"children":[["$","title",null,{"children":"500: This page couldn’t load"}],["$","style",null,{"dangerouslySetInnerHTML":{"__html":":root {--next-error-bg: #fff;--next-error-text: #171717;--next-error-title: #171717;--next-error-message: #171717;--next-error-digest: #666666;--next-error-btn-text: #fff;--next-error-btn-bg: #171717;--next-error-btn-border: none;--next-error-btn-secondary-text: #171717;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(0,0,0,0.08);}@media (prefers-color-scheme: dark) {:root {--next-error-bg: #0a0a0a;--next-error-text: #ededed;--next-error-title: #ededed;--next-error-message: #ededed;--next-error-digest: #a0a0a0;--next-error-btn-text: #0a0a0a;--next-error-btn-bg: #ededed;--next-error-btn-border: none;--next-error-btn-secondary-text: #ededed;--next-error-btn-secondary-bg: transparent;--next-error-btn-secondary-border: 1px solid rgba(255,255,255,0.14);}}body { margin: 0; color: var(--next-error-text); background: var(--next-error-bg); }"}}]]}],["$","body",null,{"children":["$","div",null,{"style":{"fontFamily":"system-ui,\"Segoe UI\",Roboto,Helvetica,Arial,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\"","height":"100vh","display":"flex","alignItems":"center","justifyContent":"center"},"children":["$","div",null,{"style":{"marginTop":"-32px","maxWidth":"325px","padding":"32px 28px","textAlign":"left"},"children":[["$","svg",null,{"width":"32","height":"32","viewBox":"-0.2 -1.5 32 32","fill":"none","style":{"marginBottom":"24px"},"children":["$","path",null,{"d":"M16.9328 0C18.0839 0.000116771 19.1334 0.658832 19.634 1.69531L31.4299 26.1309C32.0708 27.4588 31.1036 28.9999 29.6291 29H2.00215C0.527541 29 -0.439628 27.4588 0.201371 26.1309L11.9973 1.69531C12.4979 0.658823 13.5474 7.75066e-05 14.6984 0H16.9328ZM3.59493 26H28.0363L16.9328 3H14.6984L3.59493 26ZM15.8156 19C16.9202 19.0001 17.8156 19.8955 17.8156 21C17.8156 22.1045 16.9202 22.9999 15.8156 23C14.7111 23 13.8156 22.1046 13.8156 21C13.8156 19.8954 14.7111 19 15.8156 19ZM17.3156 16.5H14.3156V8.5H17.3156V16.5Z","fill":"var(--next-error-title)"}]}],["$","h1",null,{"style":{"fontSize":"24px","fontWeight":500,"letterSpacing":"-0.02em","lineHeight":"32px","margin":"0 0 12px 0","color":"var(--next-error-title)"},"children":"This page couldn’t load"}],["$","p",null,{"style":{"fontSize":"14px","fontWeight":400,"lineHeight":"21px","margin":"0 0 20px 0","color":"var(--next-error-message)"},"children":"A server error occurred. Reload to try again."}],["$","form",null,{"style":{"margin":0},"children":["$","button",null,{"type":"submit","style":{"display":"inline-flex","alignItems":"center","justifyContent":"center","height":"32px","padding":"0 12px","fontSize":"14px","fontWeight":500,"lineHeight":"20px","borderRadius":"6px","cursor":"pointer","color":"var(--next-error-btn-text)","background":"var(--next-error-btn-bg)","border":"var(--next-error-btn-border)"},"children":"Reload"}]}]]}]}]}]]}],null,["$","$L2",null,{"children":["$","$3",null,{"name":"Next.MetadataOutlet","children":"$@4"}]}]]}],"isPartial":false,"staleTime":300,"varyParams":null,"buildId":"HSR1kI5kYuEYQoBEIrPgc"}
5
5
  4:null