@codemem/server 0.26.2 → 0.27.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.
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","names":[],"sources":["../src/middleware.ts","../src/request-rate-limit.ts","../src/routes/config.ts","../src/helpers.ts","../src/routes/memory.ts","../src/routes/observer-status.ts","../src/routes/raw-events.ts","../src/routes/stats.ts","../src/routes/sync.ts","../src/index.ts"],"sourcesContent":["/**\n * CORS and cross-origin protection middleware.\n *\n * Ports Python's reject_cross_origin() logic from codemem/viewer_http.py.\n * GETs are allowed from any origin (viewer is local-only).\n * Mutations (POST/DELETE/PATCH/PUT) require an Origin header matching a\n * loopback address, or are rejected with 403.\n */\n\nimport type { Context, Next } from \"hono\";\nimport { createMiddleware } from \"hono/factory\";\n\nconst LOOPBACK_HOSTS = new Set([\"127.0.0.1\", \"localhost\", \"::1\"]);\n\n/**\n * Check whether an Origin header value is a valid loopback URL.\n * Mirrors Python's _is_allowed_loopback_origin_url().\n */\nfunction isLoopbackOrigin(origin: string): boolean {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(origin);\n\t} catch {\n\t\treturn false;\n\t}\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") return false;\n\tif (url.username || url.password) return false;\n\treturn LOOPBACK_HOSTS.has(url.hostname);\n}\n\n/** HTTP methods that mutate state and require origin validation. */\nconst UNSAFE_METHODS = new Set([\"POST\", \"DELETE\", \"PATCH\", \"PUT\"]);\n\n/**\n * Check whether a missing-Origin request looks like a cross-site browser\n * request. Matches Python's `_is_unsafe_missing_origin()`:\n *\n * - Sec-Fetch-Site present and NOT same-origin/same-site/none → unsafe\n * - Referer present and NOT loopback → unsafe\n * - Otherwise → safe (CLI / programmatic caller, no browser context)\n */\nfunction isUnsafeMissingOrigin(c: Context): boolean {\n\tconst secFetchSite = (c.req.header(\"Sec-Fetch-Site\") ?? \"\").trim().toLowerCase();\n\tif (secFetchSite && ![\"same-origin\", \"same-site\", \"none\"].includes(secFetchSite)) {\n\t\treturn true;\n\t}\n\tconst referer = c.req.header(\"Referer\");\n\tif (!referer) return false;\n\treturn !isLoopbackOrigin(referer);\n}\n\n/**\n * Cross-origin protection middleware.\n *\n * Ports Python's `reject_cross_origin(missing_origin_policy=\"reject_if_unsafe\")`:\n *\n * - GET/HEAD/OPTIONS: allowed from any origin (viewer is local-only).\n * - POST/DELETE/PATCH/PUT:\n * - Origin present + loopback → allowed (browser on localhost)\n * - Origin present + non-loopback → rejected 403\n * - No Origin + no suspicious browser signals → allowed (CLI callers)\n * - No Origin + suspicious Sec-Fetch-Site/Referer → rejected 403\n *\n * For same-origin requests (no Origin header) on safe methods, no\n * Access-Control-Allow-Origin is set — the browser doesn't need it.\n * For valid loopback origins, ACAO is echoed back.\n */\nexport function originGuard() {\n\treturn createMiddleware(async (c: Context, next: Next) => {\n\t\tconst origin = c.req.header(\"Origin\");\n\t\tconst method = c.req.method;\n\n\t\tif (UNSAFE_METHODS.has(method)) {\n\t\t\tif (origin) {\n\t\t\t\t// Origin present — must be loopback\n\t\t\t\tif (!isLoopbackOrigin(origin)) {\n\t\t\t\t\treturn c.json({ error: \"forbidden\" }, 403);\n\t\t\t\t}\n\t\t\t\t// Valid loopback origin — echo it for CORS\n\t\t\t\tc.header(\"Access-Control-Allow-Origin\", origin);\n\t\t\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, DELETE, OPTIONS\");\n\t\t\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\t\t} else {\n\t\t\t\t// No Origin — reject only if browser signals indicate cross-site\n\t\t\t\t// (matches Python's reject_if_unsafe policy for API endpoints)\n\t\t\t\tif (isUnsafeMissingOrigin(c)) {\n\t\t\t\t\treturn c.json({ error: \"forbidden\" }, 403);\n\t\t\t\t}\n\t\t\t\t// CLI / programmatic caller — no CORS headers needed\n\t\t\t}\n\t\t} else if (origin && isLoopbackOrigin(origin)) {\n\t\t\t// Safe method with valid origin — echo for preflight\n\t\t\tc.header(\"Access-Control-Allow-Origin\", origin);\n\t\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, DELETE, OPTIONS\");\n\t\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\t}\n\t\t// No origin or non-loopback on safe method: no ACAO header set.\n\t\t// Browser enforces same-origin; we don't set permissive headers.\n\n\t\tawait next();\n\t});\n}\n\n/**\n * Handle OPTIONS preflight requests.\n * Returns 204 with appropriate CORS headers for loopback origins.\n */\nexport function preflightHandler() {\n\treturn createMiddleware(async (c: Context, next: Next) => {\n\t\tif (c.req.method !== \"OPTIONS\") {\n\t\t\tawait next();\n\t\t\treturn;\n\t\t}\n\t\tconst origin = c.req.header(\"Origin\");\n\t\tif (origin && isLoopbackOrigin(origin)) {\n\t\t\tc.header(\"Access-Control-Allow-Origin\", origin);\n\t\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, DELETE, OPTIONS\");\n\t\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\t\tc.header(\"Access-Control-Max-Age\", \"86400\");\n\t\t\treturn c.body(null, 204);\n\t\t}\n\t\treturn c.body(null, 204);\n\t});\n}\n","import { RateLimiter } from \"limiter\";\n\nexport interface InMemoryRequestRateLimiter {\n\tcheck(key: string, limit: number): { allowed: boolean; retryAfterS: number };\n}\n\nexport function createInMemoryRequestRateLimiter(windowMs = 60_000): InMemoryRequestRateLimiter {\n\tconst safeWindowMs = Math.max(1000, Math.trunc(windowMs));\n\tconst buckets = new Map<string, { limiter: RateLimiter; lastUsedAt: number }>();\n\tlet checks = 0;\n\n\tfunction estimatedRetryAfterS(limit: number): number {\n\t\treturn Math.max(1, Math.ceil(safeWindowMs / Math.max(1, limit) / 1000));\n\t}\n\n\tfunction cleanupExpiredBuckets(currentNow: number): void {\n\t\tif (buckets.size < 64 || checks % 64 !== 0) return;\n\t\tconst staleBefore = currentNow - safeWindowMs * 10;\n\t\tfor (const [key, bucket] of buckets) {\n\t\t\tif (bucket.lastUsedAt < staleBefore) buckets.delete(key);\n\t\t}\n\t}\n\n\treturn {\n\t\tcheck(key: string, limit: number) {\n\t\t\tchecks += 1;\n\t\t\tconst currentNow = Date.now();\n\t\t\tcleanupExpiredBuckets(currentNow);\n\t\t\tconst safeLimit = Math.max(1, Math.trunc(limit));\n\t\t\tconst bucketKey = `${safeLimit}:${key}`;\n\t\t\tlet bucket = buckets.get(bucketKey);\n\t\t\tif (!bucket) {\n\t\t\t\tbucket = {\n\t\t\t\t\tlimiter: new RateLimiter({\n\t\t\t\t\t\ttokensPerInterval: safeLimit,\n\t\t\t\t\t\tinterval: safeWindowMs,\n\t\t\t\t\t\tfireImmediately: true,\n\t\t\t\t\t}),\n\t\t\t\t\tlastUsedAt: currentNow,\n\t\t\t\t};\n\t\t\t\tbuckets.set(bucketKey, bucket);\n\t\t\t}\n\t\t\tbucket.lastUsedAt = currentNow;\n\t\t\tif (bucket.limiter.tryRemoveTokens(1)) {\n\t\t\t\treturn { allowed: true, retryAfterS: 0 };\n\t\t\t}\n\t\t\treturn { allowed: false, retryAfterS: estimatedRetryAfterS(safeLimit) };\n\t\t},\n\t};\n}\n","/**\n * Config routes — GET /api/config, POST /api/config.\n *\n * Ports the user-facing config read/write path from Python's\n * codemem/viewer_routes/config.py, scoped to the TS runtime's current needs.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n\tCODEMEM_CONFIG_ENV_OVERRIDES,\n\tgetCodememConfigPath,\n\tgetCodememEnvOverrides,\n\tlistObserverProviderOptions,\n\ttype RawEventSweeper,\n\treadCodememConfigFile,\n\tstripJsonComments,\n\tstripTrailingCommas,\n\twriteCodememConfigFile,\n} from \"@codemem/core\";\nimport { Hono } from \"hono\";\n\ntype ConfigData = Record<string, unknown>;\n\nconst REDACTED_VALUE = \"[redacted]\";\n\nconst RUNTIMES = new Set([\"api_http\", \"claude_sidecar\"]);\nconst AUTH_SOURCES = new Set([\"auto\", \"env\", \"file\", \"command\", \"none\"]);\nconst HOT_RELOAD_KEYS = new Set([\"raw_events_sweeper_interval_s\"]);\nconst PROTECTED_WRITE_KEYS = new Set<string>([\n\t\"claude_command\",\n\t\"observer_base_url\",\n\t\"observer_auth_file\",\n\t\"observer_auth_command\",\n\t\"observer_headers\",\n\t\"sync_coordinator_url\",\n] as const);\nconst SECRET_CONFIG_KEYS = new Set<string>([\n\t\"observer_auth_file\",\n\t\"observer_auth_command\",\n\t\"observer_headers\",\n\t\"sync_coordinator_admin_secret\",\n] as const);\nconst ALLOWED_KEYS = [\n\t\"claude_command\",\n\t\"observer_base_url\",\n\t\"observer_provider\",\n\t\"observer_model\",\n\t\"observer_tier_routing_enabled\",\n\t\"observer_simple_model\",\n\t\"observer_simple_temperature\",\n\t\"observer_rich_model\",\n\t\"observer_rich_temperature\",\n\t\"observer_rich_openai_use_responses\",\n\t\"observer_rich_reasoning_effort\",\n\t\"observer_rich_reasoning_summary\",\n\t\"observer_rich_max_output_tokens\",\n\t\"observer_runtime\",\n\t\"observer_auth_source\",\n\t\"observer_auth_file\",\n\t\"observer_auth_command\",\n\t\"observer_auth_timeout_ms\",\n\t\"observer_auth_cache_ttl_s\",\n\t\"observer_headers\",\n\t\"observer_max_chars\",\n\t\"pack_observation_limit\",\n\t\"pack_session_limit\",\n\t\"sync_enabled\",\n\t\"sync_retention_enabled\",\n\t\"sync_retention_max_age_days\",\n\t\"sync_retention_max_size_mb\",\n\t\"sync_host\",\n\t\"sync_port\",\n\t\"sync_interval_s\",\n\t\"sync_mdns\",\n\t\"sync_coordinator_url\",\n\t\"sync_coordinator_group\",\n\t\"sync_coordinator_timeout_s\",\n\t\"sync_coordinator_presence_ttl_s\",\n\t\"raw_events_sweeper_interval_s\",\n] as const;\n\nconst DEFAULTS: ConfigData = {\n\tclaude_command: [\"claude\"],\n\tobserver_runtime: \"api_http\",\n\tobserver_auth_source: \"auto\",\n\tobserver_tier_routing_enabled: false,\n\tobserver_rich_openai_use_responses: false,\n\tobserver_auth_command: [],\n\tobserver_auth_timeout_ms: 1500,\n\tobserver_auth_cache_ttl_s: 300,\n\tobserver_headers: {},\n\tobserver_max_chars: 12000,\n\tpack_observation_limit: 50,\n\tpack_session_limit: 10,\n\tsync_enabled: false,\n\tsync_retention_enabled: false,\n\tsync_retention_max_age_days: 30,\n\tsync_retention_max_size_mb: 512,\n\tsync_host: \"0.0.0.0\",\n\tsync_port: 7337,\n\tsync_interval_s: 120,\n\tsync_mdns: true,\n\tsync_coordinator_timeout_s: 3,\n\tsync_coordinator_presence_ttl_s: 180,\n\traw_events_sweeper_interval_s: 30,\n};\n\nexport interface ConfigRouteOptions {\n\tgetSweeper?: () => RawEventSweeper | null;\n}\n\nfunction loadProviderOptions(): string[] {\n\treturn listObserverProviderOptions();\n}\n\nfunction getConfigPath(): string {\n\tconst envPath = process.env.CODEMEM_CONFIG;\n\tif (envPath) return envPath.replace(/^~/, homedir());\n\tconst configDir = join(homedir(), \".config\", \"codemem\");\n\tconst candidates = [join(configDir, \"config.json\"), join(configDir, \"config.jsonc\")];\n\treturn candidates.find((p) => existsSync(p)) ?? join(configDir, \"config.json\");\n}\n\nfunction readConfigFile(configPath: string): ConfigData {\n\tif (!existsSync(configPath)) return {};\n\ttry {\n\t\tlet text = readFileSync(configPath, \"utf-8\").trim();\n\t\tif (!text) return {};\n\t\ttry {\n\t\t\treturn JSON.parse(text) as ConfigData;\n\t\t} catch {\n\t\t\ttext = stripTrailingCommas(stripJsonComments(text));\n\t\t\treturn JSON.parse(text) as ConfigData;\n\t\t}\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction getEffectiveConfig(configData: ConfigData): ConfigData {\n\tconst effective: ConfigData = { ...DEFAULTS, ...configData };\n\tfor (const [key, envVar] of Object.entries(CODEMEM_CONFIG_ENV_OVERRIDES) as Array<\n\t\t[string, string]\n\t>) {\n\t\tconst val = process.env[envVar];\n\t\tif (val != null && val !== \"\") effective[key] = val;\n\t}\n\treturn effective;\n}\n\nfunction redactConfigValue(key: string, value: unknown): unknown {\n\tif (value == null || !SECRET_CONFIG_KEYS.has(key)) return value;\n\tif (Array.isArray(value)) return value.length > 0 ? REDACTED_VALUE : [];\n\tif (typeof value === \"object\") {\n\t\treturn Object.keys(value as Record<string, unknown>).length > 0 ? REDACTED_VALUE : {};\n\t}\n\tif (typeof value === \"string\") return value.trim() ? REDACTED_VALUE : \"\";\n\treturn REDACTED_VALUE;\n}\n\nfunction sanitizeConfigForResponse(configData: ConfigData): ConfigData {\n\tconst sanitized: ConfigData = {};\n\tfor (const [key, value] of Object.entries(configData)) {\n\t\tsanitized[key] = redactConfigValue(key, value);\n\t}\n\treturn sanitized;\n}\n\nfunction configValuesEqual(left: unknown, right: unknown): boolean {\n\tif (Object.is(left, right)) return true;\n\tif (left == null || right == null) return left == null && right == null;\n\tif (typeof left === \"object\" || typeof right === \"object\") {\n\t\treturn JSON.stringify(left) === JSON.stringify(right);\n\t}\n\treturn false;\n}\n\nfunction partitionViewerUpdates(\n\tupdates: ConfigData,\n\tbeforeConfig: ConfigData,\n): { allowedUpdates: ConfigData; error: string | null } {\n\tconst allowedUpdates: ConfigData = {};\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\tif (!PROTECTED_WRITE_KEYS.has(key)) {\n\t\t\tallowedUpdates[key] = value;\n\t\t\tcontinue;\n\t\t}\n\t\tif (SECRET_CONFIG_KEYS.has(key) && value === REDACTED_VALUE) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (configValuesEqual(value, beforeConfig[key])) {\n\t\t\tcontinue;\n\t\t}\n\t\treturn {\n\t\t\tallowedUpdates: {},\n\t\t\terror: `${key} cannot be changed from the viewer API; edit the config file or environment instead`,\n\t\t};\n\t}\n\treturn { allowedUpdates, error: null };\n}\n\nfunction parsePositiveInt(value: unknown, allowZero = false): number | null {\n\tif (typeof value === \"boolean\") return null;\n\tconst parsed =\n\t\ttypeof value === \"number\"\n\t\t\t? value\n\t\t\t: typeof value === \"string\" && /^-?\\d+$/.test(value.trim())\n\t\t\t\t? Number(value.trim())\n\t\t\t\t: Number.NaN;\n\tif (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;\n\tif (allowZero) return parsed >= 0 ? parsed : null;\n\treturn parsed > 0 ? parsed : null;\n}\n\nfunction parseFiniteNumber(value: unknown, allowZero = true): number | null {\n\tif (typeof value === \"boolean\") return null;\n\tconst parsed =\n\t\ttypeof value === \"number\"\n\t\t\t? value\n\t\t\t: typeof value === \"string\" && value.trim().length > 0\n\t\t\t\t? Number(value.trim())\n\t\t\t\t: Number.NaN;\n\tif (!Number.isFinite(parsed)) return null;\n\tif (allowZero) return parsed >= 0 ? parsed : null;\n\treturn parsed > 0 ? parsed : null;\n}\n\nfunction asStringMap(value: unknown): Record<string, string> | null {\n\tif (value == null || typeof value !== \"object\" || Array.isArray(value)) return null;\n\tconst parsed: Record<string, string> = {};\n\tfor (const [key, item] of Object.entries(value)) {\n\t\tif (typeof item !== \"string\") return null;\n\t\tconst stripped = key.trim();\n\t\tif (!stripped) return null;\n\t\tparsed[stripped] = item;\n\t}\n\treturn parsed;\n}\n\nfunction asExecutableArgv(value: unknown): string[] | null {\n\tif (!Array.isArray(value)) return null;\n\tconst argv: string[] = [];\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\") return null;\n\t\tconst token = item.trim();\n\t\tif (!token) return null;\n\t\targv.push(token);\n\t}\n\treturn argv;\n}\n\nfunction validateAndApplyUpdate(\n\tconfigData: ConfigData,\n\tkey: (typeof ALLOWED_KEYS)[number],\n\tvalue: unknown,\n\tproviders: Set<string>,\n): string | null {\n\tif (value == null || value === \"\") {\n\t\tdelete configData[key];\n\t\treturn null;\n\t}\n\tif (key === \"observer_provider\") {\n\t\tif (typeof value !== \"string\") return \"observer_provider must be string\";\n\t\tconst provider = value.trim().toLowerCase();\n\t\tconst savedBaseUrl = configData.observer_base_url;\n\t\tconst hasSavedBaseUrl = typeof savedBaseUrl === \"string\" && savedBaseUrl.trim().length > 0;\n\t\tif (!providers.has(provider) && !hasSavedBaseUrl) {\n\t\t\treturn \"observer_provider must match a configured provider\";\n\t\t}\n\t\tconfigData[key] = provider;\n\t\treturn null;\n\t}\n\tif (key === \"observer_runtime\") {\n\t\tif (typeof value !== \"string\") return \"observer_runtime must be string\";\n\t\tconst runtime = value.trim().toLowerCase();\n\t\tif (!RUNTIMES.has(runtime)) {\n\t\t\treturn \"observer_runtime must be one of: api_http, claude_sidecar\";\n\t\t}\n\t\tconfigData[key] = runtime;\n\t\treturn null;\n\t}\n\tif (key === \"observer_auth_source\") {\n\t\tif (typeof value !== \"string\") return \"observer_auth_source must be string\";\n\t\tconst source = value.trim().toLowerCase();\n\t\tif (!AUTH_SOURCES.has(source)) {\n\t\t\treturn \"observer_auth_source must be one of: auto, env, file, command, none\";\n\t\t}\n\t\tconfigData[key] = source;\n\t\treturn null;\n\t}\n\tif (key === \"claude_command\" || key === \"observer_auth_command\") {\n\t\tconst argv = asExecutableArgv(value);\n\t\tif (argv == null) return `${key} must be string array`;\n\t\tif (argv.length > 0) configData[key] = argv;\n\t\telse delete configData[key];\n\t\treturn null;\n\t}\n\tif (key === \"observer_headers\") {\n\t\tconst headers = asStringMap(value);\n\t\tif (headers == null) return \"observer_headers must be object of string values\";\n\t\tif (Object.keys(headers).length > 0) configData[key] = headers;\n\t\telse delete configData[key];\n\t\treturn null;\n\t}\n\tif (key === \"sync_enabled\" || key === \"sync_retention_enabled\" || key === \"sync_mdns\") {\n\t\tif (typeof value !== \"boolean\") return `${key} must be boolean`;\n\t\tconfigData[key] = value;\n\t\treturn null;\n\t}\n\tif (key === \"observer_tier_routing_enabled\" || key === \"observer_rich_openai_use_responses\") {\n\t\tif (typeof value !== \"boolean\") return `${key} must be boolean`;\n\t\tconfigData[key] = value;\n\t\treturn null;\n\t}\n\tif (\n\t\tkey === \"observer_base_url\" ||\n\t\tkey === \"observer_model\" ||\n\t\tkey === \"observer_simple_model\" ||\n\t\tkey === \"observer_rich_model\" ||\n\t\tkey === \"observer_rich_reasoning_effort\" ||\n\t\tkey === \"observer_rich_reasoning_summary\" ||\n\t\tkey === \"observer_auth_file\" ||\n\t\tkey === \"sync_host\" ||\n\t\tkey === \"sync_coordinator_url\" ||\n\t\tkey === \"sync_coordinator_group\"\n\t) {\n\t\tif (typeof value !== \"string\") return `${key} must be string`;\n\t\tconst trimmed = value.trim();\n\t\tif (!trimmed) delete configData[key];\n\t\telse configData[key] = trimmed;\n\t\treturn null;\n\t}\n\tif (key === \"observer_simple_temperature\" || key === \"observer_rich_temperature\") {\n\t\tconst parsed = parseFiniteNumber(value, true);\n\t\tif (parsed == null) return `${key} must be non-negative number`;\n\t\tconfigData[key] = parsed;\n\t\treturn null;\n\t}\n\tconst allowZero = key === \"observer_auth_cache_ttl_s\";\n\tconst parsed = parsePositiveInt(value, allowZero);\n\tif (parsed == null) return `${key} must be ${allowZero ? \"non-negative int\" : \"int\"}`;\n\tconfigData[key] = parsed;\n\treturn null;\n}\n\nfunction applyRuntimeEffects(changedKeys: string[], opts: ConfigRouteOptions): string[] {\n\tconst applied: string[] = [];\n\tif (changedKeys.includes(\"raw_events_sweeper_interval_s\")) {\n\t\tconst configValue = readCodememConfigFile().raw_events_sweeper_interval_s;\n\t\tconst seconds =\n\t\t\ttypeof configValue === \"number\"\n\t\t\t\t? configValue\n\t\t\t\t: Number.parseInt(String(configValue ?? \"\"), 10);\n\t\tif (Number.isFinite(seconds) && seconds > 0) {\n\t\t\tprocess.env.CODEMEM_RAW_EVENTS_SWEEPER_INTERVAL_MS = String(seconds * 1000);\n\t\t} else {\n\t\t\tdelete process.env.CODEMEM_RAW_EVENTS_SWEEPER_INTERVAL_MS;\n\t\t}\n\t\topts.getSweeper?.()?.notifyConfigChanged();\n\t\tapplied.push(\"raw_events_sweeper_interval_s\");\n\t}\n\treturn applied;\n}\n\nexport function configRoutes(opts: ConfigRouteOptions = {}) {\n\tconst app = new Hono();\n\n\tapp.get(\"/api/config\", (c) => {\n\t\tconst configPath = getConfigPath();\n\t\tconst configData = readConfigFile(configPath);\n\t\tconst effective = getEffectiveConfig(configData);\n\t\treturn c.json({\n\t\t\tpath: configPath,\n\t\t\tconfig: sanitizeConfigForResponse(configData),\n\t\t\tdefaults: DEFAULTS,\n\t\t\teffective: sanitizeConfigForResponse(effective),\n\t\t\tenv_overrides: getCodememEnvOverrides(),\n\t\t\tprotected_keys: [...PROTECTED_WRITE_KEYS].sort(),\n\t\t\tproviders: loadProviderOptions(),\n\t\t});\n\t});\n\n\tapp.post(\"/api/config\", async (c) => {\n\t\tlet payload: unknown;\n\t\ttry {\n\t\t\tpayload = (await c.req.json()) as unknown;\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tif (payload == null || typeof payload !== \"object\" || Array.isArray(payload)) {\n\t\t\treturn c.json({ error: \"payload must be an object\" }, 400);\n\t\t}\n\t\tif (\n\t\t\t\"config\" in payload &&\n\t\t\t(payload as ConfigData).config != null &&\n\t\t\t(typeof (payload as ConfigData).config !== \"object\" ||\n\t\t\t\tArray.isArray((payload as ConfigData).config))\n\t\t) {\n\t\t\treturn c.json({ error: \"config must be an object\" }, 400);\n\t\t}\n\t\tconst updates =\n\t\t\t\"config\" in payload &&\n\t\t\t(payload as ConfigData).config != null &&\n\t\t\ttypeof (payload as ConfigData).config === \"object\" &&\n\t\t\t!Array.isArray((payload as ConfigData).config)\n\t\t\t\t? ((payload as ConfigData).config as ConfigData)\n\t\t\t\t: (payload as ConfigData);\n\n\t\tconst configPath = getCodememConfigPath();\n\t\tconst beforeConfig = readCodememConfigFile();\n\t\tconst { allowedUpdates, error: protectedKeyError } = partitionViewerUpdates(\n\t\t\tupdates,\n\t\t\tbeforeConfig,\n\t\t);\n\t\tif (protectedKeyError) {\n\t\t\treturn c.json({ error: protectedKeyError }, 403);\n\t\t}\n\n\t\tconst beforeEffective = getEffectiveConfig(beforeConfig);\n\t\tconst nextConfig: ConfigData = { ...beforeConfig };\n\t\tconst providers = new Set(loadProviderOptions());\n\n\t\tconst touchedKeys = ALLOWED_KEYS.filter((key) => key in allowedUpdates);\n\t\tfor (const key of ALLOWED_KEYS) {\n\t\t\tif (!(key in allowedUpdates)) continue;\n\t\t\tconst error = validateAndApplyUpdate(nextConfig, key, allowedUpdates[key], providers);\n\t\t\tif (error) return c.json({ error }, 400);\n\t\t}\n\n\t\tlet savedPath: string;\n\t\ttry {\n\t\t\tsavedPath = writeCodememConfigFile(nextConfig, configPath);\n\t\t} catch {\n\t\t\treturn c.json({ error: \"failed to write config\" }, 500);\n\t\t}\n\n\t\tconst afterEffective = getEffectiveConfig(nextConfig);\n\t\tconst savedChangedKeys = ALLOWED_KEYS.filter((key) => beforeConfig[key] !== nextConfig[key]);\n\t\tconst effectiveChangedKeys = ALLOWED_KEYS.filter(\n\t\t\t(key) => beforeEffective[key] !== afterEffective[key],\n\t\t);\n\t\tconst envOverrides = getCodememEnvOverrides();\n\t\tconst ignoredByEnvKeys = savedChangedKeys.filter(\n\t\t\t(key) => !effectiveChangedKeys.includes(key) && key in envOverrides,\n\t\t);\n\t\tconst runtimeChangedKeys = [\n\t\t\t...new Set([...touchedKeys, ...savedChangedKeys, ...effectiveChangedKeys]),\n\t\t];\n\t\tconst hotReloadedKeys = applyRuntimeEffects(runtimeChangedKeys, opts);\n\t\tconst restartRequiredKeys = effectiveChangedKeys.filter(\n\t\t\t(key) => !HOT_RELOAD_KEYS.has(key) && !(key in envOverrides),\n\t\t);\n\n\t\treturn c.json({\n\t\t\tpath: savedPath,\n\t\t\tconfig: sanitizeConfigForResponse(nextConfig),\n\t\t\teffective: sanitizeConfigForResponse(afterEffective),\n\t\t\tprotected_keys: [...PROTECTED_WRITE_KEYS].sort(),\n\t\t\teffects: {\n\t\t\t\tsaved_keys: savedChangedKeys,\n\t\t\t\teffective_keys: effectiveChangedKeys,\n\t\t\t\thot_reloaded_keys: hotReloadedKeys,\n\t\t\t\trestart_required_keys: restartRequiredKeys,\n\t\t\t\tignored_by_env_keys: ignoredByEnvKeys,\n\t\t\t\twarnings: ignoredByEnvKeys.map(\n\t\t\t\t\t(key) =>\n\t\t\t\t\t\t`${key} is currently controlled by ${envOverrides[key]}; saved config will not take effect until that override is removed.`,\n\t\t\t\t),\n\t\t\t},\n\t\t});\n\t});\n\n\treturn app;\n}\n","import { parseStrictInteger } from \"@codemem/core\";\n\n/**\n * Shared helpers for viewer-server routes.\n */\n\n/**\n * Parse a JSON string that should be an array of strings.\n * Returns an empty array on null, invalid JSON, or non-array values.\n * Mirrors Python's store._safe_json_list().\n */\nexport function safeJsonList(raw: string | null | undefined): string[] {\n\tif (raw == null) return [];\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\tif (!Array.isArray(parsed)) return [];\n\t\treturn parsed.filter((item): item is string => typeof item === \"string\");\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Parse a query parameter as an integer, returning the default on failure.\n */\nexport function queryInt(value: string | undefined, defaultValue: number): number {\n\tif (value == null) return defaultValue;\n\tconst parsed = parseStrictInteger(value);\n\treturn parsed == null ? defaultValue : parsed;\n}\n\n/**\n * Parse a query parameter as a boolean flag.\n * Recognizes \"1\", \"true\", \"yes\" as truthy.\n */\nexport function queryBool(value: string | undefined): boolean {\n\tif (value == null) return false;\n\treturn value === \"1\" || value === \"true\" || value === \"yes\";\n}\n","/**\n * Memory routes — observations, summaries, sessions, projects, pack, artifacts.\n */\n\nimport type { MemoryStore } from \"@codemem/core\";\nimport {\n\tbuildFilterClausesWithContext,\n\tcanonicalMemoryKind,\n\tfromJson,\n\tisSummaryLikeMemory as isCoreSummaryLikeMemory,\n\tparseStrictInteger,\n\tschema,\n} from \"@codemem/core\";\nimport { desc, eq, inArray, isNotNull } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { Hono } from \"hono\";\nimport { queryInt } from \"../helpers.js\";\n\ntype StoreFactory = () => MemoryStore;\n\ntype OwnershipContext = {\n\tactorId: string;\n\tclaimedPeerIds: Set<string>;\n\tdeviceId: string;\n\tlegacyActorIds: Set<string>;\n};\n\nfunction cleanOwnershipValue(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst trimmed = value.trim();\n\treturn trimmed ? trimmed : null;\n}\n\nfunction buildOwnershipContext(store: MemoryStore): OwnershipContext {\n\tconst claimedPeerIds = new Set(store.sameActorPeerIds());\n\treturn {\n\t\tactorId: store.actorId,\n\t\tclaimedPeerIds,\n\t\tdeviceId: store.deviceId,\n\t\tlegacyActorIds: new Set(Array.from(claimedPeerIds, (peerId) => `legacy-sync:${peerId}`)),\n\t};\n}\n\nfunction memoryOwnedBySelf(\n\trow: Record<string, unknown>,\n\townership: OwnershipContext,\n\tmetadata = fromJson((row.metadata_json as string) ?? null),\n): boolean {\n\tconst meta = metadata as Record<string, unknown>;\n\tconst actorId = cleanOwnershipValue(row.actor_id) ?? cleanOwnershipValue(meta.actor_id);\n\tif (actorId === ownership.actorId) return true;\n\n\tconst deviceId =\n\t\tcleanOwnershipValue(row.origin_device_id) ?? cleanOwnershipValue(meta.origin_device_id);\n\tif (deviceId === ownership.deviceId) return true;\n\tif (deviceId && ownership.claimedPeerIds.has(deviceId)) return true;\n\tif (actorId && ownership.legacyActorIds.has(actorId)) return true;\n\n\treturn false;\n}\n\nfunction serializeMemoryRow(\n\townership: OwnershipContext,\n\trow: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst metadata = fromJson((row.metadata_json as string) ?? null);\n\tconst item = {\n\t\t...row,\n\t\tkind: canonicalMemoryKind((row.kind as string | null | undefined) ?? null, row.metadata_json),\n\t\tmetadata_json: metadata,\n\t};\n\treturn {\n\t\t...item,\n\t\towned_by_self: memoryOwnedBySelf(row, ownership, metadata),\n\t};\n}\n\n/**\n * Attach session project/cwd fields to memory items.\n */\nfunction attachSessionFields(store: MemoryStore, items: Record<string, unknown>[]): void {\n\tconst sessionIds: number[] = [];\n\tconst seen = new Set<number>();\n\tfor (const item of items) {\n\t\tconst value = item.session_id;\n\t\tif (value == null) continue;\n\t\tconst sid = Number(value);\n\t\tif (Number.isNaN(sid) || seen.has(sid)) continue;\n\t\tseen.add(sid);\n\t\tsessionIds.push(sid);\n\t}\n\tif (sessionIds.length === 0) return;\n\n\tconst d = drizzle(store.db, { schema });\n\tconst rows = d\n\t\t.select({\n\t\t\tid: schema.sessions.id,\n\t\t\tproject: schema.sessions.project,\n\t\t\tcwd: schema.sessions.cwd,\n\t\t})\n\t\t.from(schema.sessions)\n\t\t.where(inArray(schema.sessions.id, sessionIds))\n\t\t.all();\n\n\tconst bySession = new Map<number, { project: string; cwd: string }>();\n\tfor (const row of rows) {\n\t\tconst projectRaw = String(row.project ?? \"\").trim();\n\t\tconst project = projectRaw ? projectBasename(projectRaw) : \"\";\n\t\tconst cwd = String(row.cwd ?? \"\");\n\t\tbySession.set(row.id, { project, cwd });\n\t}\n\n\tfor (const item of items) {\n\t\tconst sid = Number(item.session_id);\n\t\tif (Number.isNaN(sid)) continue;\n\t\tconst fields = bySession.get(sid);\n\t\tif (!fields) continue;\n\t\titem.project ??= fields.project;\n\t\titem.cwd ??= fields.cwd;\n\t}\n}\n\n/**\n * Extract the basename of a project path.\n * Strips \"fatal:\" prefixed values.\n */\nfunction projectBasename(raw: string): string {\n\tif (raw.toLowerCase().startsWith(\"fatal:\")) return \"\";\n\tconst parts = raw.replace(/\\\\/g, \"/\").split(\"/\");\n\treturn parts[parts.length - 1] ?? raw;\n}\n\nfunction normalizeScope(raw: string | undefined): \"mine\" | \"theirs\" | undefined {\n\tconst value = String(raw ?? \"\")\n\t\t.trim()\n\t\t.toLowerCase();\n\tif (value === \"mine\" || value === \"theirs\") return value;\n\treturn undefined;\n}\n\nfunction queryMemoryPage(\n\tstore: MemoryStore,\n\toptions: {\n\t\tlimit: number;\n\t\toffset: number;\n\t\tproject?: string;\n\t\tscope?: \"mine\" | \"theirs\";\n\t},\n): Record<string, unknown>[] {\n\tconst filters: Record<string, unknown> = {};\n\tif (options.project) filters.project = options.project;\n\tif (options.scope) filters.ownership_scope = options.scope;\n\n\tconst filterResult = buildFilterClausesWithContext(filters, {\n\t\tactorId: store.actorId,\n\t\tdeviceId: store.deviceId,\n\t});\n\tconst clauses = [\"memory_items.active = 1\", ...filterResult.clauses];\n\tconst where = clauses.join(\" AND \");\n\tconst from = filterResult.joinSessions\n\t\t? \"memory_items JOIN sessions ON sessions.id = memory_items.session_id\"\n\t\t: \"memory_items\";\n\n\tconst rows = store.db\n\t\t.prepare(\n\t\t\t`SELECT memory_items.* FROM ${from}\n\t\t\t WHERE ${where}\n\t\t\t ORDER BY memory_items.created_at DESC\n\t\t\t LIMIT ? OFFSET ?`,\n\t\t)\n\t\t.all(...filterResult.params, options.limit + 1, options.offset) as Record<string, unknown>[];\n\n\tconst ownership = buildOwnershipContext(store);\n\treturn rows.map((row) => serializeMemoryRow(ownership, row));\n}\n\nfunction isSummaryLikeMemory(item: Record<string, unknown>): boolean {\n\treturn isCoreSummaryLikeMemory({\n\t\tkind: item.kind as string | null | undefined,\n\t\tmetadata: item.metadata_json,\n\t});\n}\n\nfunction selectMemoryPage(\n\tstore: MemoryStore,\n\toptions: {\n\t\tlimit: number;\n\t\toffset: number;\n\t\tproject?: string;\n\t\tscope?: \"mine\" | \"theirs\";\n\t\tmatcher: (item: Record<string, unknown>) => boolean;\n\t},\n): Record<string, unknown>[] {\n\tconst pageSize = Math.max(options.limit + options.offset + 10, 50);\n\tlet rawOffset = 0;\n\tconst matched: Record<string, unknown>[] = [];\n\n\twhile (matched.length < options.offset + options.limit + 1) {\n\t\tconst page = queryMemoryPage(store, {\n\t\t\tlimit: pageSize,\n\t\t\toffset: rawOffset,\n\t\t\tproject: options.project,\n\t\t\tscope: options.scope,\n\t\t});\n\t\tif (page.length === 0) break;\n\t\tmatched.push(...page.filter(options.matcher));\n\t\tif (page.length < pageSize) break;\n\t\trawOffset += page.length;\n\t}\n\n\treturn matched.slice(options.offset, options.offset + options.limit + 1);\n}\n\nexport function memoryRoutes(getStore: StoreFactory) {\n\tconst app = new Hono();\n\n\t// GET /api/sessions\n\tapp.get(\"/api/sessions\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst limit = queryInt(c.req.query(\"limit\"), 20);\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst rows = d\n\t\t\t\t.select()\n\t\t\t\t.from(schema.sessions)\n\t\t\t\t.orderBy(desc(schema.sessions.started_at))\n\t\t\t\t.limit(limit)\n\t\t\t\t.all();\n\t\t\tconst items = rows.map((row) => ({\n\t\t\t\t...row,\n\t\t\t\tmetadata_json: fromJson(row.metadata_json),\n\t\t\t}));\n\t\t\treturn c.json({ items });\n\t\t}\n\t});\n\n\t// GET /api/projects\n\tapp.get(\"/api/projects\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst rows = d\n\t\t\t\t.selectDistinct({ project: schema.sessions.project })\n\t\t\t\t.from(schema.sessions)\n\t\t\t\t.where(isNotNull(schema.sessions.project))\n\t\t\t\t.all();\n\t\t\tconst projects = [\n\t\t\t\t...new Set(\n\t\t\t\t\trows\n\t\t\t\t\t\t.map((r) => String(r.project ?? \"\").trim())\n\t\t\t\t\t\t.filter((p) => p && !p.toLowerCase().startsWith(\"fatal:\"))\n\t\t\t\t\t\t.map((p) => projectBasename(p))\n\t\t\t\t\t\t.filter(Boolean),\n\t\t\t\t),\n\t\t\t].sort();\n\t\t\treturn c.json({ projects });\n\t\t}\n\t});\n\n\t// GET /api/observations (aliased from /api/memories)\n\tapp.get(\"/api/memories\", (c) => {\n\t\tconst search = new URL(c.req.url).search;\n\t\treturn c.redirect(`/api/observations${search}`, 301);\n\t});\n\n\tapp.get(\"/api/observations\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst limit = Math.max(1, queryInt(c.req.query(\"limit\"), 20));\n\t\t\tconst offset = Math.max(0, queryInt(c.req.query(\"offset\"), 0));\n\t\t\tconst project = c.req.query(\"project\") || undefined;\n\t\t\tconst scope = normalizeScope(c.req.query(\"scope\"));\n\t\t\tconst items = selectMemoryPage(store, {\n\t\t\t\tlimit,\n\t\t\t\toffset,\n\t\t\t\tproject,\n\t\t\t\tscope,\n\t\t\t\tmatcher: (item) => !isSummaryLikeMemory(item),\n\t\t\t});\n\t\t\tconst hasMore = items.length > limit;\n\t\t\tconst result = hasMore ? items.slice(0, limit) : items;\n\t\t\tconst asRecords = result as unknown as Record<string, unknown>[];\n\t\t\tattachSessionFields(store, asRecords);\n\t\t\treturn c.json({\n\t\t\t\titems: asRecords,\n\t\t\t\tpagination: {\n\t\t\t\t\tlimit,\n\t\t\t\t\toffset,\n\t\t\t\t\tnext_offset: hasMore ? offset + result.length : null,\n\t\t\t\t\thas_more: hasMore,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t});\n\n\t// GET /api/summaries\n\tapp.get(\"/api/summaries\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst limit = Math.max(1, queryInt(c.req.query(\"limit\"), 50));\n\t\t\tconst offset = Math.max(0, queryInt(c.req.query(\"offset\"), 0));\n\t\t\tconst project = c.req.query(\"project\") || undefined;\n\t\t\tconst scope = normalizeScope(c.req.query(\"scope\"));\n\t\t\tconst items = selectMemoryPage(store, {\n\t\t\t\tlimit,\n\t\t\t\toffset,\n\t\t\t\tproject,\n\t\t\t\tscope,\n\t\t\t\tmatcher: (item) => isSummaryLikeMemory(item),\n\t\t\t});\n\t\t\tconst hasMore = items.length > limit;\n\t\t\tconst result = hasMore ? items.slice(0, limit) : items;\n\t\t\tconst asRecords = result as unknown as Record<string, unknown>[];\n\t\t\tattachSessionFields(store, asRecords);\n\t\t\treturn c.json({\n\t\t\t\titems: asRecords,\n\t\t\t\tpagination: {\n\t\t\t\t\tlimit,\n\t\t\t\t\toffset,\n\t\t\t\t\tnext_offset: hasMore ? offset + result.length : null,\n\t\t\t\t\thas_more: hasMore,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t});\n\n\t// GET /api/session (aggregate counts)\n\tapp.get(\"/api/session\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst project = c.req.query(\"project\") || null;\n\t\t\tconst count = (sql: string, ...params: unknown[]): number => {\n\t\t\t\tconst row = store.db.prepare(sql).get(...params) as Record<string, unknown> | undefined;\n\t\t\t\treturn Number(row?.total ?? 0);\n\t\t\t};\n\n\t\t\tlet prompts: number;\n\t\t\tlet artifacts: number;\n\t\t\tlet memories: number;\n\t\t\tlet observations: number;\n\t\t\tconst countObservations = (scopeProject?: string) => {\n\t\t\t\tlet offset = 0;\n\t\t\t\tlet total = 0;\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst page = queryMemoryPage(store, {\n\t\t\t\t\t\tlimit: 200,\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tproject: scopeProject,\n\t\t\t\t\t});\n\t\t\t\t\tif (page.length === 0) break;\n\t\t\t\t\ttotal += page.filter((item) => !isSummaryLikeMemory(item)).length;\n\t\t\t\t\tif (page.length < 200) break;\n\t\t\t\t\toffset += page.length;\n\t\t\t\t}\n\t\t\t\treturn total;\n\t\t\t};\n\t\t\tif (project) {\n\t\t\t\tprompts = count(\"SELECT COUNT(*) AS total FROM user_prompts WHERE project = ?\", project);\n\t\t\t\tartifacts = count(\n\t\t\t\t\t`SELECT COUNT(*) AS total FROM artifacts\n\t\t\t\t\t JOIN sessions ON sessions.id = artifacts.session_id\n\t\t\t\t\t WHERE sessions.project = ?`,\n\t\t\t\t\tproject,\n\t\t\t\t);\n\t\t\t\tmemories = count(\n\t\t\t\t\t`SELECT COUNT(*) AS total FROM memory_items\n\t\t\t\t\t JOIN sessions ON sessions.id = memory_items.session_id\n\t\t\t\t\t WHERE sessions.project = ?`,\n\t\t\t\t\tproject,\n\t\t\t\t);\n\t\t\t\tobservations = countObservations(project);\n\t\t\t} else {\n\t\t\t\tprompts = count(\"SELECT COUNT(*) AS total FROM user_prompts\");\n\t\t\t\tartifacts = count(\"SELECT COUNT(*) AS total FROM artifacts\");\n\t\t\t\tmemories = count(\"SELECT COUNT(*) AS total FROM memory_items\");\n\t\t\t\tobservations = countObservations();\n\t\t\t}\n\t\t\tconst total = prompts + artifacts + memories;\n\t\t\treturn c.json({ total, memories, artifacts, prompts, observations });\n\t\t}\n\t});\n\n\t// GET /api/pack\n\tapp.get(\"/api/pack\", async (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst context = c.req.query(\"context\") || \"\";\n\t\t\tif (!context) {\n\t\t\t\treturn c.json({ error: \"context required\" }, 400);\n\t\t\t}\n\t\t\tconst limit = queryInt(c.req.query(\"limit\"), 10);\n\t\t\tconst tokenBudgetStr = c.req.query(\"token_budget\");\n\t\t\tlet tokenBudget: number | undefined;\n\t\t\tif (tokenBudgetStr) {\n\t\t\t\ttokenBudget = parseStrictInteger(tokenBudgetStr) ?? undefined;\n\t\t\t\tif (tokenBudget === undefined) {\n\t\t\t\t\treturn c.json({ error: \"token_budget must be int\" }, 400);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst project = c.req.query(\"project\") || undefined;\n\t\t\tconst filters: { project?: string } = {};\n\t\t\tif (project) filters.project = project;\n\t\t\tconst pack = await store.buildMemoryPackAsync(context, limit, tokenBudget ?? null, filters);\n\t\t\treturn c.json(pack);\n\t\t}\n\t});\n\n\tapp.post(\"/api/pack/trace\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst parsed = await c.req.json().catch(() => Symbol.for(\"invalid-json\"));\n\t\tif (parsed === Symbol.for(\"invalid-json\")) {\n\t\t\treturn c.json({ error: \"invalid json body\" }, 400);\n\t\t}\n\t\tconst body = parsed as {\n\t\t\tcontext?: unknown;\n\t\t\tlimit?: unknown;\n\t\t\ttoken_budget?: unknown;\n\t\t\tproject?: unknown;\n\t\t\tworking_set_files?: unknown;\n\t\t} | null;\n\t\tconst context = typeof body?.context === \"string\" ? body.context.trim() : \"\";\n\t\tif (!context) {\n\t\t\treturn c.json({ error: \"context required\" }, 400);\n\t\t}\n\t\tconst limit =\n\t\t\tbody?.limit == null\n\t\t\t\t? 10\n\t\t\t\t: typeof body.limit === \"number\" && Number.isInteger(body.limit) && body.limit >= 1\n\t\t\t\t\t? body.limit\n\t\t\t\t\t: null;\n\t\tif (limit == null) {\n\t\t\treturn c.json({ error: \"limit must be a positive int\" }, 400);\n\t\t}\n\t\tlet tokenBudget: number | null = null;\n\t\tif (body?.token_budget != null) {\n\t\t\tif (\n\t\t\t\ttypeof body.token_budget !== \"number\" ||\n\t\t\t\t!Number.isInteger(body.token_budget) ||\n\t\t\t\tbody.token_budget < 0\n\t\t\t) {\n\t\t\t\treturn c.json({ error: \"token_budget must be int\" }, 400);\n\t\t\t}\n\t\t\ttokenBudget = body.token_budget;\n\t\t}\n\t\tconst project = typeof body?.project === \"string\" && body.project.trim() ? body.project : null;\n\t\tif (body?.working_set_files != null && !Array.isArray(body.working_set_files)) {\n\t\t\treturn c.json({ error: \"working_set_files must be an array of strings\" }, 400);\n\t\t}\n\t\tif (\n\t\t\tArray.isArray(body?.working_set_files) &&\n\t\t\tbody.working_set_files.some((value) => typeof value !== \"string\")\n\t\t) {\n\t\t\treturn c.json({ error: \"working_set_files must be an array of strings\" }, 400);\n\t\t}\n\t\tconst workingSetFiles = Array.isArray(body?.working_set_files) ? body.working_set_files : [];\n\t\tconst filters: { project?: string; working_set_paths?: string[] } = {};\n\t\tif (project) filters.project = project;\n\t\tif (workingSetFiles.length > 0) filters.working_set_paths = workingSetFiles;\n\t\tconst trace = await store.buildMemoryPackTraceAsync(context, limit, tokenBudget, filters);\n\t\treturn c.json(trace);\n\t});\n\n\t// GET /api/memory\n\tapp.get(\"/api/memory\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst limit = queryInt(c.req.query(\"limit\"), 20);\n\t\t\tconst kind = c.req.query(\"kind\") || undefined;\n\t\t\tconst project = c.req.query(\"project\") || undefined;\n\t\t\tconst filters: Record<string, unknown> = {};\n\t\t\tif (kind) filters.kind = kind;\n\t\t\tif (project) filters.project = project;\n\t\t\tconst items = store.recent(limit, filters);\n\t\t\tconst asRecords = items as unknown as Record<string, unknown>[];\n\t\t\tattachSessionFields(store, asRecords);\n\t\t\treturn c.json({ items: asRecords });\n\t\t}\n\t});\n\n\t// GET /api/artifacts\n\tapp.get(\"/api/artifacts\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst sessionIdStr = c.req.query(\"session_id\");\n\t\t\tif (!sessionIdStr) {\n\t\t\t\treturn c.json({ error: \"session_id required\" }, 400);\n\t\t\t}\n\t\t\tconst sessionId = parseStrictInteger(sessionIdStr);\n\t\t\tif (sessionId == null) {\n\t\t\t\treturn c.json({ error: \"session_id must be int\" }, 400);\n\t\t\t}\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst rows = d\n\t\t\t\t.select()\n\t\t\t\t.from(schema.artifacts)\n\t\t\t\t.where(eq(schema.artifacts.session_id, sessionId))\n\t\t\t\t.all();\n\t\t\treturn c.json({ items: rows });\n\t\t}\n\t});\n\n\t// POST /api/memories/visibility\n\tapp.post(\"/api/memories/visibility\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid JSON\" }, 400);\n\t\t}\n\t\tconst memoryId = parseStrictInteger(\n\t\t\ttypeof body.memory_id === \"string\" ? body.memory_id : String(body.memory_id ?? \"\"),\n\t\t);\n\t\tif (memoryId == null || memoryId <= 0) {\n\t\t\treturn c.json({ error: \"memory_id must be int\" }, 400);\n\t\t}\n\t\tconst visibility = String(body.visibility ?? \"\").trim();\n\t\tif (visibility !== \"private\" && visibility !== \"shared\") {\n\t\t\treturn c.json({ error: \"visibility must be private or shared\" }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst item = store.updateMemoryVisibility(memoryId, visibility);\n\t\t\treturn c.json({ item });\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\tif (msg.includes(\"not found\")) return c.json({ error: msg }, 404);\n\t\t\tif (msg.includes(\"not owned\")) return c.json({ error: msg }, 403);\n\t\t\treturn c.json({ error: msg }, 400);\n\t\t}\n\t});\n\n\t// POST /api/memories/forget\n\tapp.post(\"/api/memories/forget\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid JSON\" }, 400);\n\t\t}\n\t\tconst memoryId = parseStrictInteger(\n\t\t\ttypeof body.memory_id === \"string\" ? body.memory_id : String(body.memory_id ?? \"\"),\n\t\t);\n\t\tif (memoryId == null || memoryId <= 0) {\n\t\t\treturn c.json({ error: \"memory_id must be int\" }, 400);\n\t\t}\n\n\t\tconst row = drizzle(store.db, { schema })\n\t\t\t.select()\n\t\t\t.from(schema.memoryItems)\n\t\t\t.where(eq(schema.memoryItems.id, memoryId))\n\t\t\t.get();\n\t\tif (!row) {\n\t\t\treturn c.json({ error: \"memory not found\" }, 404);\n\t\t}\n\t\tconst ownership = buildOwnershipContext(store);\n\t\tif (!memoryOwnedBySelf(row, ownership)) {\n\t\t\treturn c.json({ error: \"memory not owned by this device\" }, 403);\n\t\t}\n\t\tif (Number(row.active ?? 1) === 0 || row.deleted_at != null) {\n\t\t\treturn c.json({ status: \"ok\" });\n\t\t}\n\n\t\ttry {\n\t\t\tstore.forget(memoryId);\n\t\t\treturn c.json({ status: \"ok\" });\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\tif (msg.includes(\"not found\")) return c.json({ error: msg }, 404);\n\t\t\tif (msg.includes(\"not owned\")) return c.json({ error: msg }, 403);\n\t\t\tif (msg.includes(\"sync_rebootstrap_in_progress\")) return c.json({ error: msg }, 409);\n\t\t\treturn c.json({ error: msg }, 400);\n\t\t}\n\t});\n\n\treturn app;\n}\n","/**\n * Observer status route — GET /api/observer-status.\n *\n * Ports Python's viewer_routes/observer_status.py.\n * Returns observer runtime info, credential availability, and queue status.\n */\n\nimport type { ObserverClient } from \"@codemem/core\";\nimport { type MemoryStore, probeAvailableCredentials, type RawEventSweeper } from \"@codemem/core\";\nimport { Hono } from \"hono\";\n\ntype StoreFactory = () => MemoryStore;\n\nexport interface ObserverStatusDeps {\n\tgetStore: StoreFactory;\n\tgetSweeper: () => RawEventSweeper | null;\n\tgetObserver?: () => ObserverClient | null;\n}\n\nfunction normalizeActiveObserver(active: ReturnType<ObserverClient[\"getStatus\"]> | null) {\n\tif (!active) return null;\n\treturn {\n\t\t...active,\n\t\tauth: {\n\t\t\t...active.auth,\n\t\t\tmethod: active.auth.type,\n\t\t\ttoken_present: active.auth.hasToken,\n\t\t},\n\t};\n}\n\nfunction buildFailureImpact(\n\tlatestFailure: Record<string, unknown> | null,\n\tqueueTotals: { pending: number; sessions: number },\n\tauthBackoff: { active: boolean; remainingS: number },\n): string | null {\n\tif (!latestFailure) return null;\n\tif (authBackoff.active) {\n\t\treturn `Queue retries paused for ~${authBackoff.remainingS}s after an observer auth failure.`;\n\t}\n\tif (queueTotals.pending > 0) {\n\t\treturn `${queueTotals.pending} queued raw events across ${queueTotals.sessions} session(s) are waiting on a successful flush.`;\n\t}\n\treturn \"Failed flush batches are pending retry.\";\n}\n\nexport function observerStatusRoutes(deps?: ObserverStatusDeps) {\n\tconst app = new Hono();\n\n\tapp.get(\"/api/observer-status\", (c) => {\n\t\tconst store = deps?.getStore();\n\t\tconst sweeper = deps?.getSweeper();\n\t\tconst observer = deps?.getObserver?.() ?? null;\n\n\t\t// Stub fallback when store doesn't have the required methods (e.g. tests with mock store)\n\t\tif (!store || typeof store.rawEventBacklogTotals !== \"function\") {\n\t\t\treturn c.json({\n\t\t\t\tactive: null,\n\t\t\t\tavailable_credentials: {},\n\t\t\t\tlatest_failure: null,\n\t\t\t\tqueue: {\n\t\t\t\t\tpending: 0,\n\t\t\t\t\tsessions: 0,\n\t\t\t\t\tauth_backoff_active: false,\n\t\t\t\t\tauth_backoff_remaining_s: 0,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tconst queueTotals = store.rawEventBacklogTotals();\n\t\tconst authBackoff = sweeper?.authBackoffStatus() ?? { active: false, remainingS: 0 };\n\t\tconst latestFailure = store.latestRawEventFlushFailure();\n\t\tconst active = normalizeActiveObserver(observer?.getStatus() ?? null);\n\t\tconst availableCredentials = probeAvailableCredentials();\n\t\tconst shouldShowFailure =\n\t\t\tlatestFailure != null && (authBackoff.active || queueTotals.pending > 0);\n\n\t\tconst failureWithImpact =\n\t\t\tshouldShowFailure && latestFailure\n\t\t\t\t? { ...latestFailure, impact: buildFailureImpact(latestFailure, queueTotals, authBackoff) }\n\t\t\t\t: null;\n\n\t\treturn c.json({\n\t\t\tactive,\n\t\t\tavailable_credentials: availableCredentials,\n\t\t\tlatest_failure: failureWithImpact,\n\t\t\tqueue: {\n\t\t\t\t...queueTotals,\n\t\t\t\tauth_backoff_active: authBackoff.active,\n\t\t\t\tauth_backoff_remaining_s: authBackoff.remainingS,\n\t\t\t},\n\t\t});\n\t});\n\n\treturn app;\n}\n","/**\n * Raw events routes — GET & POST /api/raw-events, GET /api/raw-events/status,\n * POST /api/claude-hooks.\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { MemoryStore, RawEventSweeper } from \"@codemem/core\";\nimport { buildRawEventEnvelopeFromHook, schema, stripPrivateObj } from \"@codemem/core\";\nimport { desc } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { Hono } from \"hono\";\nimport { queryInt } from \"../helpers.js\";\n\ntype StoreFactory = () => MemoryStore;\n\nconst MAX_RAW_EVENTS_BODY_BYTES =\n\tNumber.parseInt(process.env.CODEMEM_RAW_EVENTS_MAX_BODY_BYTES ?? \"\", 10) || 1048576;\n\n/** Keys to check (in priority order) when resolving a session stream id. */\nconst SESSION_ID_KEYS = [\n\t\"session_stream_id\",\n\t\"session_id\",\n\t\"stream_id\",\n\t\"opencode_session_id\",\n] as const;\n\n/**\n * Resolve a session stream id from a payload object.\n * Checks multiple field aliases. Throws on conflicting values.\n */\nfunction resolveSessionStreamId(payload: Record<string, unknown>): string | null {\n\tconst values = new Map<string, string>();\n\tfor (const key of SESSION_ID_KEYS) {\n\t\tconst value = payload[key];\n\t\tif (value == null) continue;\n\t\tif (typeof value !== \"string\") throw new Error(`${key} must be string`);\n\t\tconst text = value.trim();\n\t\tif (text) values.set(key, text);\n\t}\n\tif (values.size === 0) return null;\n\tconst unique = new Set(values.values());\n\tif (unique.size > 1) throw new Error(\"conflicting session id fields\");\n\t// Return the first matching key's value (preserves priority order)\n\tfor (const key of SESSION_ID_KEYS) {\n\t\tconst v = values.get(key);\n\t\tif (v) return v;\n\t}\n\treturn null;\n}\n\n/**\n * Parse and validate a JSON object body, enforcing size limits.\n * Returns the parsed payload or a Hono Response on error.\n */\nasync function parseJsonObjectBody(\n\tc: {\n\t\treq: { header: (name: string) => string | undefined; text: () => Promise<string> };\n\t\tjson: (data: unknown, status?: number) => Response;\n\t},\n\tmaxBytes: number,\n): Promise<Record<string, unknown> | Response> {\n\tconst contentLength = Number.parseInt(c.req.header(\"content-length\") ?? \"0\", 10);\n\tif (Number.isNaN(contentLength) || contentLength < 0) {\n\t\treturn c.json({ error: \"invalid content-length\" }, 400);\n\t}\n\tif (contentLength > maxBytes) {\n\t\treturn c.json({ error: \"payload too large\", max_bytes: maxBytes }, 413);\n\t}\n\tlet raw: string;\n\ttry {\n\t\traw = await c.req.text();\n\t} catch {\n\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t}\n\tif (Buffer.byteLength(raw, \"utf-8\") > maxBytes) {\n\t\treturn c.json({ error: \"payload too large\", max_bytes: maxBytes }, 413);\n\t}\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = raw ? JSON.parse(raw) : {};\n\t} catch {\n\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t}\n\tif (parsed == null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\treturn c.json({ error: \"payload must be an object\" }, 400);\n\t}\n\treturn parsed as Record<string, unknown>;\n}\n\n/** Nudge the sweeper safely — never crashes the caller. */\nfunction nudgeSweeper(\n\tsweeper: RawEventSweeper | null | undefined,\n\tsessionIds: Iterable<string>,\n\tsource = \"opencode\",\n): void {\n\ttry {\n\t\tfor (const sessionId of sessionIds) {\n\t\t\tsweeper?.nudge(sessionId, source);\n\t\t}\n\t} catch {\n\t\t// never crash the request if sweeper nudge fails\n\t}\n}\n\nexport function rawEventsRoutes(getStore: StoreFactory, sweeper?: RawEventSweeper | null) {\n\tconst app = new Hono();\n\n\t// GET /api/raw-events (compat endpoint for stats panel)\n\tapp.get(\"/api/raw-events\", (c) => {\n\t\tconst store = getStore();\n\t\tconst totals = store.rawEventBacklogTotals();\n\t\treturn c.json(totals);\n\t});\n\n\t// GET /api/raw-events/status\n\tapp.get(\"/api/raw-events/status\", (c) => {\n\t\tconst store = getStore();\n\t\tconst limit = queryInt(c.req.query(\"limit\"), 25);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst rows = d\n\t\t\t.select({\n\t\t\t\tsource: schema.rawEventSessions.source,\n\t\t\t\tstream_id: schema.rawEventSessions.stream_id,\n\t\t\t\topencode_session_id: schema.rawEventSessions.opencode_session_id,\n\t\t\t\tcwd: schema.rawEventSessions.cwd,\n\t\t\t\tproject: schema.rawEventSessions.project,\n\t\t\t\tstarted_at: schema.rawEventSessions.started_at,\n\t\t\t\tlast_seen_ts_wall_ms: schema.rawEventSessions.last_seen_ts_wall_ms,\n\t\t\t\tlast_received_event_seq: schema.rawEventSessions.last_received_event_seq,\n\t\t\t\tlast_flushed_event_seq: schema.rawEventSessions.last_flushed_event_seq,\n\t\t\t\tupdated_at: schema.rawEventSessions.updated_at,\n\t\t\t})\n\t\t\t.from(schema.rawEventSessions)\n\t\t\t.orderBy(desc(schema.rawEventSessions.updated_at))\n\t\t\t.limit(limit)\n\t\t\t.all();\n\t\tconst items = rows.map((row) => {\n\t\t\tconst streamId = String(row.stream_id ?? row.opencode_session_id ?? \"\");\n\t\t\treturn {\n\t\t\t\t...row,\n\t\t\t\tsession_stream_id: streamId,\n\t\t\t\tsession_id: streamId,\n\t\t\t};\n\t\t});\n\t\tconst totals = store.rawEventBacklogTotals();\n\t\treturn c.json({\n\t\t\titems,\n\t\t\ttotals,\n\t\t\tingest: {\n\t\t\t\tavailable: true,\n\t\t\t\tmode: \"stream_queue\",\n\t\t\t\tmax_body_bytes: MAX_RAW_EVENTS_BODY_BYTES,\n\t\t\t},\n\t\t});\n\t});\n\n\t// POST /api/raw-events — ingest raw events from plugin\n\tapp.post(\"/api/raw-events\", async (c) => {\n\t\tconst result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);\n\t\tif (result instanceof Response) return result;\n\t\tconst payload = result;\n\n\t\tconst store = getStore();\n\t\ttry {\n\t\t\t// Validate top-level string fields\n\t\t\tconst cwd = payload.cwd;\n\t\t\tif (cwd != null && typeof cwd !== \"string\") {\n\t\t\t\treturn c.json({ error: \"cwd must be string\" }, 400);\n\t\t\t}\n\t\t\tconst project = payload.project;\n\t\t\tif (project != null && typeof project !== \"string\") {\n\t\t\t\treturn c.json({ error: \"project must be string\" }, 400);\n\t\t\t}\n\t\t\tconst startedAt = payload.started_at;\n\t\t\tif (startedAt != null && typeof startedAt !== \"string\") {\n\t\t\t\treturn c.json({ error: \"started_at must be string\" }, 400);\n\t\t\t}\n\n\t\t\t// Determine event list: batch (events array) or single-event payload\n\t\t\tlet items = payload.events;\n\t\t\tif (items == null) {\n\t\t\t\titems = [payload];\n\t\t\t}\n\t\t\tif (!Array.isArray(items)) {\n\t\t\t\treturn c.json({ error: \"events must be a list\" }, 400);\n\t\t\t}\n\n\t\t\t// Resolve default session id from top-level payload\n\t\t\tlet defaultSessionId: string;\n\t\t\ttry {\n\t\t\t\tdefaultSessionId = resolveSessionStreamId(payload) ?? \"\";\n\t\t\t} catch (err) {\n\t\t\t\treturn c.json({ error: (err as Error).message }, 400);\n\t\t\t}\n\t\t\tif (defaultSessionId.startsWith(\"msg_\")) {\n\t\t\t\treturn c.json({ error: \"invalid session id\" }, 400);\n\t\t\t}\n\n\t\t\tlet inserted = 0;\n\t\t\tconst lastSeenBySession = new Map<string, number>();\n\t\t\tconst metaBySession = new Map<string, Record<string, string>>();\n\t\t\tconst sessionIds = new Set<string>();\n\t\t\tconst batchBySession = new Map<string, Record<string, unknown>[]>();\n\n\t\t\tfor (const item of items) {\n\t\t\t\tif (item == null || typeof item !== \"object\" || Array.isArray(item)) {\n\t\t\t\t\treturn c.json({ error: \"event must be an object\" }, 400);\n\t\t\t\t}\n\t\t\t\tconst itemObj = item as Record<string, unknown>;\n\n\t\t\t\tlet itemSessionId: string | null;\n\t\t\t\ttry {\n\t\t\t\t\titemSessionId = resolveSessionStreamId(itemObj);\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn c.json({ error: (err as Error).message }, 400);\n\t\t\t\t}\n\t\t\t\tconst opencodeSessionId = String(itemSessionId ?? defaultSessionId ?? \"\");\n\t\t\t\tif (!opencodeSessionId) {\n\t\t\t\t\treturn c.json({ error: \"session id required\" }, 400);\n\t\t\t\t}\n\t\t\t\tif (opencodeSessionId.startsWith(\"msg_\")) {\n\t\t\t\t\treturn c.json({ error: \"invalid session id\" }, 400);\n\t\t\t\t}\n\n\t\t\t\tlet eventId = String(itemObj.event_id ?? \"\");\n\t\t\t\tconst eventType = String(itemObj.event_type ?? \"\");\n\t\t\t\tif (!eventType) {\n\t\t\t\t\treturn c.json({ error: \"event_type required\" }, 400);\n\t\t\t\t}\n\n\t\t\t\tconst eventSeqValue = itemObj.event_seq;\n\t\t\t\tif (eventSeqValue != null) {\n\t\t\t\t\tconst parsed = Number(eventSeqValue);\n\t\t\t\t\tif (!Number.isFinite(parsed) || parsed !== Math.floor(parsed)) {\n\t\t\t\t\t\treturn c.json({ error: \"event_seq must be int\" }, 400);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet tsWallMs = itemObj.ts_wall_ms;\n\t\t\t\tif (tsWallMs != null) {\n\t\t\t\t\tconst parsed = Number(tsWallMs);\n\t\t\t\t\tif (!Number.isFinite(parsed)) {\n\t\t\t\t\t\treturn c.json({ error: \"ts_wall_ms must be int\" }, 400);\n\t\t\t\t\t}\n\t\t\t\t\ttsWallMs = Math.floor(parsed);\n\t\t\t\t\tconst prev = lastSeenBySession.get(opencodeSessionId) ?? (tsWallMs as number);\n\t\t\t\t\tlastSeenBySession.set(opencodeSessionId, Math.max(prev, tsWallMs as number));\n\t\t\t\t}\n\n\t\t\t\tlet tsMonoMs = itemObj.ts_mono_ms;\n\t\t\t\tif (tsMonoMs != null) {\n\t\t\t\t\tconst parsed = Number(tsMonoMs);\n\t\t\t\t\tif (!Number.isFinite(parsed)) {\n\t\t\t\t\t\treturn c.json({ error: \"ts_mono_ms must be number\" }, 400);\n\t\t\t\t\t}\n\t\t\t\t\ttsMonoMs = parsed;\n\t\t\t\t}\n\n\t\t\t\tlet eventPayload = itemObj.payload;\n\t\t\t\tif (eventPayload == null) eventPayload = {};\n\t\t\t\tif (typeof eventPayload !== \"object\" || Array.isArray(eventPayload)) {\n\t\t\t\t\treturn c.json({ error: \"payload must be an object\" }, 400);\n\t\t\t\t}\n\n\t\t\t\t// Per-item meta fields\n\t\t\t\tconst itemCwd = itemObj.cwd;\n\t\t\t\tif (itemCwd != null && typeof itemCwd !== \"string\") {\n\t\t\t\t\treturn c.json({ error: \"cwd must be string\" }, 400);\n\t\t\t\t}\n\t\t\t\tconst itemProject = itemObj.project;\n\t\t\t\tif (itemProject != null && typeof itemProject !== \"string\") {\n\t\t\t\t\treturn c.json({ error: \"project must be string\" }, 400);\n\t\t\t\t}\n\t\t\t\tconst itemStartedAt = itemObj.started_at;\n\t\t\t\tif (itemStartedAt != null && typeof itemStartedAt !== \"string\") {\n\t\t\t\t\treturn c.json({ error: \"started_at must be string\" }, 400);\n\t\t\t\t}\n\n\t\t\t\t// Sanitize payload\n\t\t\t\teventPayload = stripPrivateObj(eventPayload) as Record<string, unknown>;\n\n\t\t\t\t// Generate stable event_id for legacy senders.\n\t\t\t\t// Python uses json.dumps(sort_keys=True) which recursively sorts all keys.\n\t\t\t\t// We replicate with a recursive key-sorting replacer.\n\t\t\t\tif (!eventId) {\n\t\t\t\t\tconst sortedStringify = (obj: unknown): string =>\n\t\t\t\t\t\tJSON.stringify(obj, (_key, value) => {\n\t\t\t\t\t\t\tif (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n\t\t\t\t\t\t\t\tconst sorted: Record<string, unknown> = {};\n\t\t\t\t\t\t\t\tfor (const k of Object.keys(value as Record<string, unknown>).sort()) {\n\t\t\t\t\t\t\t\t\tsorted[k] = (value as Record<string, unknown>)[k];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn sorted;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t});\n\t\t\t\t\tif (eventSeqValue != null) {\n\t\t\t\t\t\tconst rawId = sortedStringify({\n\t\t\t\t\t\t\ts: eventSeqValue,\n\t\t\t\t\t\t\tt: eventType,\n\t\t\t\t\t\t\tp: eventPayload,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst hash = createHash(\"sha256\").update(rawId, \"utf-8\").digest(\"hex\").slice(0, 16);\n\t\t\t\t\t\teventId = `legacy-seq-${eventSeqValue}-${hash}`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst rawId = sortedStringify({\n\t\t\t\t\t\t\tm: tsMonoMs ?? null,\n\t\t\t\t\t\t\tp: eventPayload,\n\t\t\t\t\t\t\tt: eventType,\n\t\t\t\t\t\t\tw: tsWallMs ?? null,\n\t\t\t\t\t\t});\n\t\t\t\t\t\teventId = `legacy-${createHash(\"sha256\").update(rawId, \"utf-8\").digest(\"hex\").slice(0, 16)}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst eventEntry: Record<string, unknown> = {\n\t\t\t\t\tevent_id: eventId,\n\t\t\t\t\tevent_type: eventType,\n\t\t\t\t\tpayload: eventPayload,\n\t\t\t\t\tts_wall_ms: tsWallMs ?? null,\n\t\t\t\t\tts_mono_ms: tsMonoMs ?? null,\n\t\t\t\t};\n\n\t\t\t\tsessionIds.add(opencodeSessionId);\n\t\t\t\tconst list = batchBySession.get(opencodeSessionId) ?? [];\n\t\t\t\tlist.push({ ...eventEntry });\n\t\t\t\tbatchBySession.set(opencodeSessionId, list);\n\n\t\t\t\tif (itemCwd || itemProject || itemStartedAt) {\n\t\t\t\t\tconst perSession = metaBySession.get(opencodeSessionId) ?? {};\n\t\t\t\t\tif (itemCwd) perSession.cwd = itemCwd as string;\n\t\t\t\t\tif (itemProject) perSession.project = itemProject as string;\n\t\t\t\t\tif (itemStartedAt) perSession.started_at = itemStartedAt as string;\n\t\t\t\t\tmetaBySession.set(opencodeSessionId, perSession);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Insert events\n\t\t\tif (sessionIds.size === 1) {\n\t\t\t\tconst singleSessionId = sessionIds.values().next().value as string;\n\t\t\t\tconst batch = batchBySession.get(singleSessionId) ?? [];\n\t\t\t\tconst result = store.recordRawEventsBatch(singleSessionId, batch);\n\t\t\t\tinserted = result.inserted;\n\t\t\t} else {\n\t\t\t\tfor (const [sid, sidEvents] of batchBySession) {\n\t\t\t\t\tconst result = store.recordRawEventsBatch(sid, sidEvents);\n\t\t\t\t\tinserted += result.inserted;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Update session metadata\n\t\t\tfor (const metaSessionId of sessionIds) {\n\t\t\t\tconst sessionMeta = metaBySession.get(metaSessionId) ?? {};\n\t\t\t\tconst applyRequestMeta = sessionIds.size === 1 || metaSessionId === defaultSessionId;\n\t\t\t\tstore.updateRawEventSessionMeta({\n\t\t\t\t\topencodeSessionId: metaSessionId,\n\t\t\t\t\tcwd:\n\t\t\t\t\t\tsessionMeta.cwd ?? (applyRequestMeta ? (cwd as string | undefined) : undefined) ?? null,\n\t\t\t\t\tproject:\n\t\t\t\t\t\tsessionMeta.project ??\n\t\t\t\t\t\t(applyRequestMeta ? (project as string | undefined) : undefined) ??\n\t\t\t\t\t\tnull,\n\t\t\t\t\tstartedAt:\n\t\t\t\t\t\tsessionMeta.started_at ??\n\t\t\t\t\t\t(applyRequestMeta ? (startedAt as string | undefined) : undefined) ??\n\t\t\t\t\t\tnull,\n\t\t\t\t\tlastSeenTsWallMs: lastSeenBySession.get(metaSessionId) ?? null,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Note per-session activity for optional debounced auto-flush.\n\t\t\tnudgeSweeper(sweeper, sessionIds);\n\n\t\t\treturn c.json({ inserted, received: (items as unknown[]).length });\n\t\t} catch (err) {\n\t\t\tconst response: Record<string, unknown> = { error: \"internal server error\" };\n\t\t\tif (process.env.CODEMEM_VIEWER_DEBUG === \"1\") {\n\t\t\t\tresponse.detail = (err as Error).message;\n\t\t\t}\n\t\t\treturn c.json(response, 500);\n\t\t}\n\t});\n\n\t// POST /api/claude-hooks — ingest Claude Code hook events\n\tapp.post(\"/api/claude-hooks\", async (c) => {\n\t\tconst result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);\n\t\tif (result instanceof Response) return result;\n\t\tconst payload = result;\n\n\t\t// Map hook payload → raw event envelope\n\t\tconst envelope = buildRawEventEnvelopeFromHook(payload);\n\t\tif (envelope === null) {\n\t\t\t// Unsupported event type or missing required fields — skip gracefully\n\t\t\treturn c.json({ inserted: 0, skipped: 1 });\n\t\t}\n\n\t\tconst store = getStore();\n\t\ttry {\n\t\t\tconst opencodeSessionId = envelope.opencode_session_id;\n\t\t\tconst source = envelope.source;\n\t\t\tconst strippedPayload = stripPrivateObj(envelope.payload) as Record<string, unknown>;\n\n\t\t\tconst inserted = store.recordRawEvent({\n\t\t\t\topencodeSessionId,\n\t\t\t\tsource,\n\t\t\t\teventId: envelope.event_id,\n\t\t\t\teventType: \"claude.hook\",\n\t\t\t\tpayload: strippedPayload,\n\t\t\t\ttsWallMs: envelope.ts_wall_ms,\n\t\t\t});\n\n\t\t\tstore.updateRawEventSessionMeta({\n\t\t\t\topencodeSessionId,\n\t\t\t\tsource,\n\t\t\t\tcwd: envelope.cwd,\n\t\t\t\tproject: envelope.project,\n\t\t\t\tstartedAt: envelope.started_at,\n\t\t\t\tlastSeenTsWallMs: envelope.ts_wall_ms,\n\t\t\t});\n\n\t\t\t// Note activity for optional debounced auto-flush.\n\t\t\tnudgeSweeper(sweeper, [opencodeSessionId], source);\n\n\t\t\treturn c.json({ inserted: inserted ? 1 : 0, skipped: 0 });\n\t\t} catch (err) {\n\t\t\tconst response: Record<string, unknown> = { error: \"internal server error\" };\n\t\t\tif (process.env.CODEMEM_VIEWER_DEBUG === \"1\") {\n\t\t\t\tresponse.detail = (err as Error).message;\n\t\t\t}\n\t\t\treturn c.json(response, 500);\n\t\t}\n\t});\n\n\treturn app;\n}\n","/**\n * Stats routes — GET /api/stats, GET /api/usage.\n *\n * Ports Python's viewer_routes/stats.py.\n */\n\nimport { listMaintenanceJobs, type MemoryStore, VERSION } from \"@codemem/core\";\nimport { Hono } from \"hono\";\n\nfunction maintenanceJobSortKey(job: {\n\tstarted_at: string | null;\n\tupdated_at: string;\n\tkind: string;\n}): [string, string] {\n\treturn [job.started_at ?? job.updated_at, job.kind];\n}\n\nfunction sortActiveMaintenanceJobs<\n\tT extends { started_at: string | null; updated_at: string; kind: string },\n>(jobs: T[]): T[] {\n\treturn [...jobs].sort((a, b) => {\n\t\tconst [aTime, aKind] = maintenanceJobSortKey(a);\n\t\tconst [bTime, bKind] = maintenanceJobSortKey(b);\n\t\tif (aTime !== bTime) return aTime.localeCompare(bTime);\n\t\treturn aKind.localeCompare(bKind);\n\t});\n}\n\n/**\n * Create stats routes. The store factory is called per-request to get a\n * fresh connection (matching the Python viewer pattern).\n */\nexport function statsRoutes(getStore: () => MemoryStore) {\n\tconst app = new Hono();\n\n\tconst parseMetadataJson = (value: unknown): Record<string, unknown> | null => {\n\t\tif (typeof value !== \"string\" || !value.trim()) return null;\n\t\ttry {\n\t\t\treturn JSON.parse(value) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t};\n\n\tapp.get(\"/api/stats\", (c) => {\n\t\tconst store = getStore();\n\t\tconst jobs = listMaintenanceJobs(store.db);\n\t\tconst activeJobs = sortActiveMaintenanceJobs(\n\t\t\tjobs.filter(\n\t\t\t\t(job) => job.status === \"pending\" || job.status === \"running\" || job.status === \"failed\",\n\t\t\t),\n\t\t).map((job) => ({\n\t\t\tkind: job.kind,\n\t\t\ttitle: job.title,\n\t\t\tstatus: job.status,\n\t\t\tmessage: job.message,\n\t\t\tprogress: job.progress,\n\t\t\terror: job.error,\n\t\t}));\n\t\treturn c.json({\n\t\t\t...store.stats(),\n\t\t\tviewer_pid: process.pid,\n\t\t\tmaintenance_jobs: activeJobs,\n\t\t});\n\t});\n\n\tapp.get(\"/api/runtime\", (c) => {\n\t\treturn c.json({\n\t\t\tversion: VERSION,\n\t\t});\n\t});\n\n\tapp.get(\"/api/usage\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst projectFilter = c.req.query(\"project\") || null;\n\t\t\tconst recentPacksQuery = projectFilter\n\t\t\t\t? store.db.prepare(\n\t\t\t\t\t\t`SELECT usage_events.id, usage_events.session_id, usage_events.event,\n\t\t\t\t\t\tusage_events.tokens_read, usage_events.tokens_written, usage_events.tokens_saved,\n\t\t\t\t\t\tusage_events.created_at, usage_events.metadata_json\n\t\t\t\t\t FROM usage_events\n\t\t\t\t\t JOIN sessions ON sessions.id = usage_events.session_id\n\t\t\t\t\t WHERE usage_events.event = 'pack' AND sessions.project = ?\n\t\t\t\t\t ORDER BY usage_events.created_at DESC\n\t\t\t\t\t LIMIT 10`,\n\t\t\t\t\t)\n\t\t\t\t: store.db.prepare(\n\t\t\t\t\t\t`SELECT id, session_id, event, tokens_read, tokens_written, tokens_saved, created_at, metadata_json\n\t\t\t\t\t FROM usage_events\n\t\t\t\t\t WHERE event = 'pack'\n\t\t\t\t\t ORDER BY created_at DESC\n\t\t\t\t\t LIMIT 10`,\n\t\t\t\t\t);\n\t\t\tconst eventsGlobal = store.db\n\t\t\t\t.prepare(\n\t\t\t\t\t`SELECT event,\n\t\t\t\t\t\tSUM(tokens_read) AS total_tokens_read,\n\t\t\t\t\t\tSUM(tokens_written) AS total_tokens_written,\n\t\t\t\t\t\tSUM(tokens_saved) AS total_tokens_saved,\n\t\t\t\t\t\tCOUNT(*) AS count\n\t\t\t\t\t FROM usage_events GROUP BY event ORDER BY event`,\n\t\t\t\t)\n\t\t\t\t.all() as Record<string, unknown>[];\n\t\t\tconst totalsGlobal = store.db\n\t\t\t\t.prepare(\n\t\t\t\t\t`SELECT COALESCE(SUM(tokens_read),0) AS tokens_read,\n\t\t\t\t\t\tCOALESCE(SUM(tokens_written),0) AS tokens_written,\n\t\t\t\t\t\tCOALESCE(SUM(tokens_saved),0) AS tokens_saved,\n\t\t\t\t\t\tCOUNT(*) AS count\n\t\t\t\t\t FROM usage_events`,\n\t\t\t\t)\n\t\t\t\t.get() as Record<string, unknown>;\n\t\t\tlet eventsFiltered: Record<string, unknown>[] | null = null;\n\t\t\tlet totalsFiltered: Record<string, unknown> | null = null;\n\t\t\tif (projectFilter) {\n\t\t\t\teventsFiltered = store.db\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t`SELECT event,\n\t\t\t\t\t\t\tSUM(tokens_read) AS total_tokens_read,\n\t\t\t\t\t\t\tSUM(tokens_written) AS total_tokens_written,\n\t\t\t\t\t\t\tSUM(tokens_saved) AS total_tokens_saved,\n\t\t\t\t\t\t\tCOUNT(*) AS count\n\t\t\t\t\t\t FROM usage_events\n\t\t\t\t\t\t JOIN sessions ON sessions.id = usage_events.session_id\n\t\t\t\t\t\t WHERE sessions.project = ?\n\t\t\t\t\t\t GROUP BY event ORDER BY event`,\n\t\t\t\t\t)\n\t\t\t\t\t.all(projectFilter) as Record<string, unknown>[];\n\t\t\t\ttotalsFiltered = store.db\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t`SELECT COALESCE(SUM(tokens_read),0) AS tokens_read,\n\t\t\t\t\t\t\tCOALESCE(SUM(tokens_written),0) AS tokens_written,\n\t\t\t\t\t\t\tCOALESCE(SUM(tokens_saved),0) AS tokens_saved,\n\t\t\t\t\t\t\tCOUNT(*) AS count\n\t\t\t\t\t\t FROM usage_events\n\t\t\t\t\t\t JOIN sessions ON sessions.id = usage_events.session_id\n\t\t\t\t\t\t WHERE sessions.project = ?`,\n\t\t\t\t\t)\n\t\t\t\t\t.get(projectFilter) as Record<string, unknown>;\n\t\t\t}\n\t\t\tconst recentPacksRaw = (\n\t\t\t\tprojectFilter ? recentPacksQuery.all(projectFilter) : recentPacksQuery.all()\n\t\t\t) as Record<string, unknown>[];\n\t\t\tconst recentPacks = recentPacksRaw.map((row) => ({\n\t\t\t\tid: Number(row.id ?? 0),\n\t\t\t\tsession_id: row.session_id == null ? null : Number(row.session_id),\n\t\t\t\tevent: String(row.event ?? \"pack\"),\n\t\t\t\ttokens_read: Number(row.tokens_read ?? 0),\n\t\t\t\ttokens_written: Number(row.tokens_written ?? 0),\n\t\t\t\ttokens_saved: Number(row.tokens_saved ?? 0),\n\t\t\t\tcreated_at: String(row.created_at ?? \"\"),\n\t\t\t\tmetadata_json: parseMetadataJson(row.metadata_json),\n\t\t\t}));\n\n\t\t\treturn c.json({\n\t\t\t\tproject: projectFilter,\n\t\t\t\tevents: projectFilter ? eventsFiltered : eventsGlobal,\n\t\t\t\ttotals: projectFilter ? totalsFiltered : totalsGlobal,\n\t\t\t\tevents_global: eventsGlobal,\n\t\t\t\ttotals_global: totalsGlobal,\n\t\t\t\tevents_filtered: eventsFiltered,\n\t\t\t\ttotals_filtered: totalsFiltered,\n\t\t\t\trecent_packs: recentPacks,\n\t\t\t});\n\t\t}\n\t});\n\n\treturn app;\n}\n","/**\n * Sync routes — status, peers, actors, attempts, pairing, mutations.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport net from \"node:net\";\nimport { dirname, join } from \"node:path\";\nimport type {\n\tCoordinatorBootstrapGrantVerification,\n\tMaintenanceJobSnapshot,\n\tMemoryStore,\n\tReplicationOp,\n\tSemanticIndexDiagnostics,\n} from \"@codemem/core\";\nimport {\n\tapplyReplicationOps,\n\tbuildBaseUrl,\n\tcleanupNonces,\n\tcoordinatorArchiveGroupAction,\n\tcoordinatorCreateGroupAction,\n\tcoordinatorCreateInviteAction,\n\tcoordinatorDisableDeviceAction,\n\tcoordinatorImportInviteAction,\n\tcoordinatorListBootstrapGrantsAction,\n\tcoordinatorListDevicesAction,\n\tcoordinatorListGroupsAction,\n\tcoordinatorListJoinRequestsAction,\n\tcoordinatorRemoveDeviceAction,\n\tcoordinatorRenameDeviceAction,\n\tcoordinatorRenameGroupAction,\n\tcoordinatorReviewJoinRequestAction,\n\tcoordinatorRevokeBootstrapGrantAction,\n\tcoordinatorStatusSnapshot,\n\tcoordinatorUnarchiveGroupAction,\n\tcreateCoordinatorReciprocalApproval,\n\tDEFAULT_TIME_WINDOW_S,\n\tensureDeviceIdentity,\n\textractReplicationOps,\n\tfingerprintPublicKey,\n\tgetSemanticIndexDiagnostics,\n\tgetSyncResetState,\n\tlistCoordinatorJoinRequests,\n\tlistMaintenanceJobs,\n\tloadMemorySnapshotPageForPeer,\n\tloadReplicationOpsForPeer,\n\tlookupCoordinatorPeers,\n\tmergeAddresses,\n\treadCoordinatorSyncConfig,\n\trecordNonce,\n\trequestJson,\n\trunSyncPass,\n\tschema,\n\tsyncProjectAllowedByFilters,\n\tsyncVisibilityAllowed,\n\tverifySignature,\n} from \"@codemem/core\";\nimport { and, count, desc, eq, max, ne } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { type Context, Hono } from \"hono\";\nimport { queryBool, queryInt, safeJsonList } from \"../helpers.js\";\nimport type { InMemoryRequestRateLimiter } from \"../request-rate-limit.js\";\n\ntype StoreFactory = () => MemoryStore;\ntype SyncRuntimeStatus = {\n\tphase:\n\t\t| \"starting\"\n\t\t| \"running\"\n\t\t| \"stopping\"\n\t\t| \"error\"\n\t\t| \"disabled\"\n\t\t| \"rebootstrapping\"\n\t\t| \"needs_attention\"\n\t\t| null;\n\tdetail?: string | null;\n};\n\ninterface SyncProtocolRouteOptions {\n\trouteRateLimit?: {\n\t\tlimiter: InMemoryRequestRateLimiter;\n\t\treadLimit: number;\n\t\tmutationLimit: number;\n\t\tunauthenticatedReadLimit: number;\n\t\tunauthenticatedMutationLimit: number;\n\t};\n}\n\nconst SYNC_STALE_AFTER_SECONDS = 10 * 60;\nconst SYNC_PROTOCOL_VERSION = \"2\";\nconst LEGACY_SYNC_ACTOR_DISPLAY_NAME = \"Legacy synced peer\";\nconst LEGACY_SHARED_WORKSPACE_ID = \"shared:legacy\";\n\ntype CoordinatorAdminReadiness = \"not_configured\" | \"partial\" | \"ready\";\n\nfunction coordinatorAdminStatusPayload(config = readCoordinatorSyncConfig()) {\n\tconst groups = config.syncCoordinatorGroups;\n\tconst activeGroup = groups[0] ?? null;\n\tconst hasUrl = Boolean(config.syncCoordinatorUrl);\n\tconst hasGroups = groups.length > 0;\n\tconst hasAdminSecret = Boolean(config.syncCoordinatorAdminSecret);\n\tlet readiness: CoordinatorAdminReadiness = \"ready\";\n\tif (!hasUrl) readiness = \"not_configured\";\n\telse if (!hasGroups || !hasAdminSecret) readiness = \"partial\";\n\treturn {\n\t\treadiness,\n\t\tcoordinator_url: config.syncCoordinatorUrl || null,\n\t\tgroups,\n\t\tactive_group: activeGroup,\n\t\thas_admin_secret: hasAdminSecret,\n\t\thas_groups: hasGroups,\n\t};\n}\n\nfunction resolveCoordinatorAdminGroup(\n\trequestedGroup: string | null | undefined,\n\tstatus: ReturnType<typeof coordinatorAdminStatusPayload>,\n): string | null {\n\tconst explicit = String(requestedGroup ?? \"\").trim();\n\tif (explicit) return explicit;\n\treturn status.active_group;\n}\n\nfunction parseInviteTtlHours(value: unknown): number | null {\n\tconst ttlHours = Number(String(value ?? 24));\n\tif (!Number.isInteger(ttlHours) || ttlHours < 1) return null;\n\treturn ttlHours;\n}\n\nfunction sortActiveMaintenanceJobs<\n\tT extends { started_at: string | null; updated_at: string; kind: string },\n>(jobs: T[]): T[] {\n\treturn [...jobs].sort((a, b) => {\n\t\tconst aTime = a.started_at ?? a.updated_at;\n\t\tconst bTime = b.started_at ?? b.updated_at;\n\t\tif (aTime !== bTime) return aTime.localeCompare(bTime);\n\t\treturn a.kind.localeCompare(b.kind);\n\t});\n}\n\nfunction summarizeMaintenanceJobs(\n\tjobs: MaintenanceJobSnapshot[],\n\tshowDiagnostics: boolean,\n): Array<Record<string, unknown>> {\n\treturn sortActiveMaintenanceJobs(\n\t\tjobs.filter((job) => [\"pending\", \"running\", \"failed\"].includes(String(job.status ?? \"\"))),\n\t).map((job) => ({\n\t\tkind: job.kind,\n\t\ttitle: job.title,\n\t\tstatus: job.status,\n\t\tprogress: job.progress,\n\t\t...(showDiagnostics\n\t\t\t? {\n\t\t\t\t\tmessage: job.message,\n\t\t\t\t\terror: job.error,\n\t\t\t\t\tmetadata: job.metadata,\n\t\t\t\t}\n\t\t\t: {}),\n\t}));\n}\n\nfunction redactSemanticIndexDiagnostics(\n\tdiagnostics: SemanticIndexDiagnostics,\n\tshowDiagnostics: boolean,\n): SemanticIndexDiagnostics {\n\tif (showDiagnostics || !diagnostics.maintenance_job) {\n\t\treturn diagnostics;\n\t}\n\tconst summary =\n\t\tdiagnostics.state === \"pending\"\n\t\t\t? \"Semantic-index catch-up is pending\"\n\t\t\t: diagnostics.state === \"failed\"\n\t\t\t\t? \"Semantic-index catch-up failed\"\n\t\t\t\t: diagnostics.state === \"degraded\"\n\t\t\t\t\t? \"Semantic index is running in degraded mode\"\n\t\t\t\t\t: diagnostics.summary;\n\treturn {\n\t\t...diagnostics,\n\t\tsummary,\n\t\tmaintenance_job: {\n\t\t\t...diagnostics.maintenance_job,\n\t\t\tmessage: null,\n\t\t\terror: null,\n\t\t},\n\t};\n}\n\nfunction syncKeysDir(): string | undefined {\n\treturn process.env.CODEMEM_KEYS_DIR?.trim() || undefined;\n}\n\nfunction intEnvOr(name: string, fallback: number): number {\n\tconst value = Number.parseInt(process.env[name] ?? \"\", 10);\n\treturn Number.isFinite(value) ? value : fallback;\n}\n\nconst MAX_SYNC_BODY_BYTES = intEnvOr(\"CODEMEM_SYNC_MAX_BODY_BYTES\", 1_048_576);\nconst MAX_SYNC_OPS = intEnvOr(\"CODEMEM_SYNC_MAX_OPS\", 2000);\n\nasync function readBoundedRequestBytes(request: Request, maxBytes: number): Promise<Buffer | null> {\n\tconst contentLength = Number.parseInt(request.headers.get(\"content-length\") ?? \"\", 10);\n\tif (Number.isFinite(contentLength) && contentLength > maxBytes) {\n\t\treturn null;\n\t}\n\tconst stream = request.body;\n\tif (!stream) return Buffer.alloc(0);\n\tconst reader = stream.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tif (!value) continue;\n\t\t\ttotal += value.byteLength;\n\t\t\tif (total > maxBytes) {\n\t\t\t\tawait reader.cancel();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tchunks.push(value);\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\treturn Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)));\n}\n\nconst PAIRING_FILTER_HINT =\n\t\"Run this on another device with codemem sync pair --accept '<payload>'. \" +\n\t\"On the accepting device, --include/--exclude control both what it sends and what it accepts from that peer.\";\n\nfunction pathWithQuery(url: string): string {\n\tconst parsed = new URL(url);\n\treturn parsed.search ? `${parsed.pathname}${parsed.search}` : parsed.pathname;\n}\n\nfunction unauthorizedPayload(reason: string, exposeReason = false): Record<string, string> {\n\tif (exposeReason && process.env.CODEMEM_SYNC_AUTH_DIAGNOSTICS === \"1\") {\n\t\treturn { error: \"unauthorized\", reason };\n\t}\n\treturn { error: \"unauthorized\" };\n}\n\nfunction authorizeSyncRequest(\n\tstore: MemoryStore,\n\trequest: { method: string; url: string; header(name: string): string | undefined },\n\tbody: Buffer,\n): { ok: boolean; reason: string; deviceId: string } {\n\tconst deviceId = (request.header(\"X-Opencode-Device\") ?? \"\").trim();\n\tconst signature = request.header(\"X-Opencode-Signature\") ?? \"\";\n\tconst timestamp = request.header(\"X-Opencode-Timestamp\") ?? \"\";\n\tconst nonce = request.header(\"X-Opencode-Nonce\") ?? \"\";\n\tif (!deviceId || !signature || !timestamp || !nonce) {\n\t\treturn { ok: false, reason: \"missing_headers\", deviceId };\n\t}\n\n\tconst peerRow = store.db\n\t\t.prepare(\n\t\t\t\"SELECT pinned_fingerprint, public_key FROM sync_peers WHERE peer_device_id = ? LIMIT 1\",\n\t\t)\n\t\t.get(deviceId) as { pinned_fingerprint: string | null; public_key: string | null } | undefined;\n\tif (!peerRow) {\n\t\treturn { ok: false, reason: \"unknown_peer\", deviceId };\n\t}\n\n\tconst pinnedFingerprint = String(peerRow.pinned_fingerprint ?? \"\").trim();\n\tconst publicKey = String(peerRow.public_key ?? \"\").trim();\n\tif (!pinnedFingerprint || !publicKey) {\n\t\treturn { ok: false, reason: \"peer_record_incomplete\", deviceId };\n\t}\n\tif (fingerprintPublicKey(publicKey) !== pinnedFingerprint) {\n\t\treturn { ok: false, reason: \"fingerprint_mismatch\", deviceId };\n\t}\n\n\tlet valid = false;\n\ttry {\n\t\tvalid = verifySignature({\n\t\t\tmethod: request.method,\n\t\t\tpathWithQuery: pathWithQuery(request.url),\n\t\t\tbodyBytes: body,\n\t\t\ttimestamp,\n\t\t\tnonce,\n\t\t\tsignature,\n\t\t\tpublicKey,\n\t\t\tdeviceId,\n\t\t});\n\t} catch {\n\t\treturn { ok: false, reason: \"signature_verification_error\", deviceId };\n\t}\n\n\tif (!valid) {\n\t\treturn { ok: false, reason: \"invalid_signature\", deviceId };\n\t}\n\n\tconst createdAt = new Date().toISOString();\n\tif (!recordNonce(store.db, deviceId, nonce, createdAt)) {\n\t\treturn { ok: false, reason: \"nonce_replay\", deviceId };\n\t}\n\n\tconst cutoff = new Date(Date.now() - DEFAULT_TIME_WINDOW_S * 2 * 1000).toISOString();\n\tcleanupNonces(store.db, cutoff);\n\treturn { ok: true, reason: \"ok\", deviceId };\n}\n\nasync function authorizeBootstrapGrantRequest(\n\tstore: MemoryStore,\n\trequest: { method: string; url: string; header(name: string): string | undefined },\n\tbody: Buffer,\n): Promise<{ ok: boolean; reason: string; deviceId: string }> {\n\tconst grantId = (request.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim();\n\tconst deviceId = (request.header(\"X-Opencode-Device\") ?? \"\").trim();\n\tconst signature = request.header(\"X-Opencode-Signature\") ?? \"\";\n\tconst timestamp = request.header(\"X-Opencode-Timestamp\") ?? \"\";\n\tconst nonce = request.header(\"X-Opencode-Nonce\") ?? \"\";\n\tif (!grantId || !deviceId || !signature || !timestamp || !nonce) {\n\t\treturn { ok: false, reason: \"missing_bootstrap_grant_headers\", deviceId };\n\t}\n\n\tconst config = readCoordinatorSyncConfig();\n\tif (!config.syncCoordinatorUrl || !config.syncCoordinatorAdminSecret) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_coordinator_not_configured\", deviceId };\n\t}\n\n\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\tlet verification: CoordinatorBootstrapGrantVerification;\n\ttry {\n\t\tconst [status, payload] = await requestJson(\n\t\t\t\"GET\",\n\t\t\t`${buildBaseUrl(config.syncCoordinatorUrl)}/v1/admin/bootstrap-grants/${encodeURIComponent(grantId)}`,\n\t\t\t{\n\t\t\t\theaders: { \"X-Codemem-Coordinator-Admin\": config.syncCoordinatorAdminSecret },\n\t\t\t\ttimeoutS: Math.max(1, config.syncCoordinatorTimeoutS),\n\t\t\t},\n\t\t);\n\t\tif (status !== 200 || !payload) {\n\t\t\treturn { ok: false, reason: \"bootstrap_grant_lookup_failed\", deviceId };\n\t\t}\n\t\tverification = payload as unknown as CoordinatorBootstrapGrantVerification;\n\t} catch {\n\t\treturn { ok: false, reason: \"bootstrap_grant_lookup_failed\", deviceId };\n\t}\n\n\tconst grant = verification.grant;\n\tconst workerEnrollment = verification.worker_enrollment;\n\tif (!grant || !workerEnrollment) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_invalid_payload\", deviceId };\n\t}\n\tif (grant.revoked_at) return { ok: false, reason: \"bootstrap_grant_revoked\", deviceId };\n\tif (String(workerEnrollment.device_id) !== String(grant.worker_device_id)) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_worker_enrollment_mismatch\", deviceId };\n\t}\n\tif (String(workerEnrollment.group_id) !== String(grant.group_id)) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_group_mismatch\", deviceId };\n\t}\n\tif (Number(workerEnrollment.enabled) !== 1) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_worker_disabled\", deviceId };\n\t}\n\tif (grant.worker_device_id !== deviceId) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_worker_mismatch\", deviceId };\n\t}\n\tif (grant.seed_device_id !== localDeviceId) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_seed_mismatch\", deviceId };\n\t}\n\tif (new Date(grant.expires_at) <= new Date()) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_expired\", deviceId };\n\t}\n\n\tlet valid = false;\n\ttry {\n\t\tvalid = verifySignature({\n\t\t\tmethod: request.method,\n\t\t\tpathWithQuery: pathWithQuery(request.url),\n\t\t\tbodyBytes: body,\n\t\t\ttimestamp,\n\t\t\tnonce,\n\t\t\tsignature,\n\t\t\tpublicKey: String(workerEnrollment.public_key),\n\t\t\tdeviceId,\n\t\t});\n\t} catch {\n\t\treturn { ok: false, reason: \"bootstrap_grant_signature_verification_error\", deviceId };\n\t}\n\tif (!valid) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_invalid_signature\", deviceId };\n\t}\n\n\tconst createdAt = new Date().toISOString();\n\tif (!recordNonce(store.db, deviceId, nonce, createdAt)) {\n\t\treturn { ok: false, reason: \"nonce_replay\", deviceId };\n\t}\n\tconst cutoff = new Date(Date.now() - DEFAULT_TIME_WINDOW_S * 2 * 1000).toISOString();\n\tcleanupNonces(store.db, cutoff);\n\treturn { ok: true, reason: \"ok\", deviceId };\n}\n\nfunction parseJsonList(value: unknown): string[] {\n\tif (value == null) return [];\n\tif (typeof value === \"string\") {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(value) as unknown;\n\t\t\tif (!Array.isArray(parsed)) return [];\n\t\t\treturn parsed.map((entry) => String(entry ?? \"\").trim()).filter(Boolean);\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\tif (!Array.isArray(value)) return [];\n\treturn value.map((entry) => String(entry ?? \"\").trim()).filter(Boolean);\n}\n\nfunction readPeerProjectFilters(\n\tstore: MemoryStore,\n\tpeerDeviceId: string,\n): { include: string[]; exclude: string[] } {\n\tconst globalConfig = readCoordinatorSyncConfig();\n\tconst row = store.db\n\t\t.prepare(\n\t\t\t\"SELECT projects_include_json, projects_exclude_json FROM sync_peers WHERE peer_device_id = ? LIMIT 1\",\n\t\t)\n\t\t.get(peerDeviceId) as\n\t\t| { projects_include_json: string | null; projects_exclude_json: string | null }\n\t\t| undefined;\n\tif (!row) {\n\t\treturn {\n\t\t\tinclude: globalConfig.syncProjectsInclude,\n\t\t\texclude: globalConfig.syncProjectsExclude,\n\t\t};\n\t}\n\tconst hasOverride = row.projects_include_json != null || row.projects_exclude_json != null;\n\tif (!hasOverride) {\n\t\treturn {\n\t\t\tinclude: globalConfig.syncProjectsInclude,\n\t\t\texclude: globalConfig.syncProjectsExclude,\n\t\t};\n\t}\n\treturn {\n\t\tinclude: parseJsonList(row.projects_include_json),\n\t\texclude: parseJsonList(row.projects_exclude_json),\n\t};\n}\n\nfunction currentProjectScope(\n\trow: Record<string, unknown>,\n\teffective?: { include: string[]; exclude: string[] },\n): Record<string, unknown> {\n\treturn {\n\t\tinclude: safeJsonList(row.projects_include_json as string | null),\n\t\texclude: safeJsonList(row.projects_exclude_json as string | null),\n\t\teffective_include:\n\t\t\teffective?.include ?? safeJsonList(row.projects_include_json as string | null),\n\t\teffective_exclude:\n\t\t\teffective?.exclude ?? safeJsonList(row.projects_exclude_json as string | null),\n\t\tinherits_global: row.projects_include_json == null && row.projects_exclude_json == null,\n\t};\n}\n\nfunction ensureLocalActorRecord(store: MemoryStore): void {\n\tconst d = drizzle(store.db, { schema });\n\tconst existing = d\n\t\t.select({ actor_id: schema.actors.actor_id })\n\t\t.from(schema.actors)\n\t\t.where(eq(schema.actors.actor_id, store.actorId))\n\t\t.get();\n\tif (existing) return;\n\tconst now = new Date().toISOString();\n\td.insert(schema.actors)\n\t\t.values({\n\t\t\tactor_id: store.actorId,\n\t\t\tdisplay_name: store.actorDisplayName,\n\t\t\tis_local: 1,\n\t\t\tstatus: \"active\",\n\t\t\tmerged_into_actor_id: null,\n\t\t\tcreated_at: now,\n\t\t\tupdated_at: now,\n\t\t})\n\t\t.run();\n}\n\nfunction findPeerDeviceIdForAddress(store: MemoryStore, address: string): string | null {\n\tconst rows = store.db\n\t\t.prepare(\"SELECT peer_device_id, addresses_json FROM sync_peers\")\n\t\t.all() as Array<{ peer_device_id: string; addresses_json: string | null }>;\n\tfor (const row of rows) {\n\t\tconst addresses = safeJsonList(row.addresses_json);\n\t\tif (addresses.includes(address)) return String(row.peer_device_id ?? \"\").trim() || null;\n\t}\n\treturn null;\n}\n\nfunction claimLegacyDeviceAsSelf(store: MemoryStore, originDeviceId: string): number {\n\tconst deviceId = String(originDeviceId || \"\").trim();\n\tif (!deviceId || deviceId === \"unknown\" || deviceId === store.deviceId) return 0;\n\tconst personalWorkspaceId = `personal:${store.actorId}`;\n\tconst result = store.db\n\t\t.prepare(\n\t\t\t`UPDATE memory_items\n\t\t\t SET actor_id = ?,\n\t\t\t actor_display_name = ?,\n\t\t\t visibility = 'private',\n\t\t\t workspace_id = ?,\n\t\t\t workspace_kind = 'personal',\n\t\t\t trust_state = 'trusted'\n\t\t\t WHERE origin_device_id = ?\n\t\t\t AND origin_device_id NOT IN (\n\t\t\t SELECT peer_device_id FROM sync_peers WHERE peer_device_id IS NOT NULL\n\t\t\t )\n\t\t\t AND (\n\t\t\t (\n\t\t\t actor_id IS NULL\n\t\t\t OR TRIM(actor_id) = ''\n\t\t\t OR actor_id LIKE 'legacy-sync:%'\n\t\t\t OR actor_id = ?\n\t\t\t )\n\t\t\t AND (\n\t\t\t actor_id IS NULL\n\t\t\t OR TRIM(actor_id) = ''\n\t\t\t OR actor_id LIKE 'legacy-sync:%'\n\t\t\t OR actor_display_name = ?\n\t\t\t OR workspace_id = ?\n\t\t\t OR trust_state = 'legacy_unknown'\n\t\t\t )\n\t\t\t )`,\n\t\t)\n\t\t.run(\n\t\t\tstore.actorId,\n\t\t\tstore.actorDisplayName,\n\t\t\tpersonalWorkspaceId,\n\t\t\tdeviceId,\n\t\t\tstore.actorId,\n\t\t\tLEGACY_SYNC_ACTOR_DISPLAY_NAME,\n\t\t\tLEGACY_SHARED_WORKSPACE_ID,\n\t\t);\n\treturn Number(result.changes ?? 0);\n}\n\nfunction peerClaimedLocalActor(store: MemoryStore, peerDeviceId: string): boolean {\n\tconst row = store.db\n\t\t.prepare(\"SELECT claimed_local_actor FROM sync_peers WHERE peer_device_id = ? LIMIT 1\")\n\t\t.get(peerDeviceId) as { claimed_local_actor: number | null } | undefined;\n\treturn Boolean(row?.claimed_local_actor);\n}\n\nfunction parseOpPayload(op: { payload_json: string | null }): Record<string, unknown> | null {\n\tif (!op.payload_json || !String(op.payload_json).trim()) return null;\n\ttry {\n\t\tconst parsed = JSON.parse(op.payload_json) as unknown;\n\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return null;\n\t\treturn parsed as Record<string, unknown>;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction redactCoordinatorStatus(\n\tcoordinator: Record<string, unknown>,\n\tshowDiag: boolean,\n): Record<string, unknown> {\n\tif (showDiag) return coordinator;\n\tconst discovered = Array.isArray(coordinator.discovered_devices)\n\t\t? coordinator.discovered_devices.map((item) => {\n\t\t\t\tif (!item || typeof item !== \"object\") return item;\n\t\t\t\tconst record = item as Record<string, unknown>;\n\t\t\t\treturn {\n\t\t\t\t\tdevice_id: record.device_id,\n\t\t\t\t\tdisplay_name: record.display_name ?? null,\n\t\t\t\t\tgroups: Array.isArray(record.groups) ? record.groups : [],\n\t\t\t\t\tlast_seen_at: record.last_seen_at ?? null,\n\t\t\t\t\texpires_at: record.expires_at ?? null,\n\t\t\t\t\tstale: Boolean(record.stale),\n\t\t\t\t\tneeds_local_approval: Boolean(record.needs_local_approval),\n\t\t\t\t\twaiting_for_peer_approval: Boolean(record.waiting_for_peer_approval),\n\t\t\t\t\tincoming_reciprocal_request_id: record.incoming_reciprocal_request_id ?? null,\n\t\t\t\t\toutgoing_reciprocal_request_id: record.outgoing_reciprocal_request_id ?? null,\n\t\t\t\t\tfingerprint: null,\n\t\t\t\t\taddresses: [],\n\t\t\t\t};\n\t\t\t})\n\t\t: [];\n\treturn {\n\t\t...coordinator,\n\t\tdiscovered_devices: discovered,\n\t};\n}\n\nasync function acceptDiscoveredPeer(\n\tstore: MemoryStore,\n\tinput: { peerDeviceId: string; fingerprint: string },\n): Promise<\n\t| { ok: true; peer_device_id: string; created: boolean; updated: boolean; name: string | null }\n\t| { ok: false; status: number; error: string; detail: string }\n> {\n\tconst config = readCoordinatorSyncConfig();\n\tif (\n\t\t!config.syncEnabled ||\n\t\t!config.syncCoordinatorUrl ||\n\t\tconfig.syncCoordinatorGroups.length === 0\n\t) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 400,\n\t\t\terror: \"coordinator_not_configured\",\n\t\t\tdetail: \"Coordinator must be configured before accepting discovered peers.\",\n\t\t};\n\t}\n\tconst discovered = await lookupCoordinatorPeers(store, config);\n\tconst match = discovered.find(\n\t\t(peer) =>\n\t\t\tString(peer.device_id ?? \"\").trim() === input.peerDeviceId &&\n\t\t\tString(peer.fingerprint ?? \"\").trim() === input.fingerprint,\n\t);\n\tif (!match) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 404,\n\t\t\terror: \"discovered_peer_not_found\",\n\t\t\tdetail: \"That discovered device is no longer available. Refresh sync status and try again.\",\n\t\t};\n\t}\n\tconst nextFingerprint = String(match.fingerprint ?? \"\").trim();\n\tconst nextPublicKey = String(match.public_key ?? \"\").trim();\n\tconst nextName = String(match.display_name ?? \"\").trim() || null;\n\tconst nextAddresses = Array.isArray(match.addresses)\n\t\t? match.addresses.filter((value): value is string => typeof value === \"string\")\n\t\t: [];\n\tif (!nextPublicKey) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"discovered_peer_missing_public_key\",\n\t\t\tdetail:\n\t\t\t\t\"This discovered device is missing its coordinator public key. Refresh sync status and try again.\",\n\t\t};\n\t}\n\n\tconst groupIds = Array.isArray(match.groups)\n\t\t? match.groups.map((value) => String(value ?? \"\").trim()).filter(Boolean)\n\t\t: [];\n\tif (groupIds.length !== 1) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"ambiguous_coordinator_group\",\n\t\t\tdetail:\n\t\t\t\tgroupIds.length > 1\n\t\t\t\t\t? \"This device is visible through multiple coordinator groups. Review the team setup before approving it here.\"\n\t\t\t\t\t: \"This device is missing coordinator group context. Refresh sync status and try again.\",\n\t\t};\n\t}\n\tconst groupId = groupIds[0] as string;\n\tconst d = drizzle(store.db, { schema });\n\tconst existing = d\n\t\t.select({\n\t\t\tpeer_device_id: schema.syncPeers.peer_device_id,\n\t\t\tpinned_fingerprint: schema.syncPeers.pinned_fingerprint,\n\t\t\tpublic_key: schema.syncPeers.public_key,\n\t\t\taddresses_json: schema.syncPeers.addresses_json,\n\t\t})\n\t\t.from(schema.syncPeers)\n\t\t.where(eq(schema.syncPeers.peer_device_id, input.peerDeviceId))\n\t\t.get();\n\tconst existingFingerprint = String(existing?.pinned_fingerprint ?? \"\").trim();\n\tif (existing && existingFingerprint && existingFingerprint !== nextFingerprint) {\n\t\treturn {\n\t\t\tok: false as const,\n\t\t\tstatus: 409,\n\t\t\terror: \"peer_conflict\",\n\t\t\tdetail:\n\t\t\t\t\"An existing peer with this device id is pinned to a different fingerprint. Remove or repair the old peer before accepting this discovered device.\",\n\t\t};\n\t}\n\tconst existingAddresses = (() => {\n\t\ttry {\n\t\t\tconst raw = JSON.parse(String(existing?.addresses_json ?? \"[]\"));\n\t\t\treturn Array.isArray(raw)\n\t\t\t\t? raw.filter((value): value is string => typeof value === \"string\")\n\t\t\t\t: [];\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t})();\n\tconst addressesJson = JSON.stringify(mergeAddresses(existingAddresses, nextAddresses));\n\tawait createCoordinatorReciprocalApproval(store, config, {\n\t\tgroupId,\n\t\trequestedDeviceId: input.peerDeviceId,\n\t});\n\tconst now = new Date().toISOString();\n\tconst result = store.db.transaction(() => {\n\t\tif (!existing) {\n\t\t\td.insert(schema.syncPeers)\n\t\t\t\t.values({\n\t\t\t\t\tpeer_device_id: input.peerDeviceId,\n\t\t\t\t\tname: nextName,\n\t\t\t\t\tpinned_fingerprint: nextFingerprint || null,\n\t\t\t\t\tpublic_key: nextPublicKey,\n\t\t\t\t\taddresses_json: addressesJson,\n\t\t\t\t\tcreated_at: now,\n\t\t\t\t\tlast_seen_at: now,\n\t\t\t\t})\n\t\t\t\t.run();\n\t\t\treturn {\n\t\t\t\tok: true as const,\n\t\t\t\tpeer_device_id: input.peerDeviceId,\n\t\t\t\tcreated: true,\n\t\t\t\tupdated: false,\n\t\t\t\tname: nextName,\n\t\t\t};\n\t\t}\n\t\td.update(schema.syncPeers)\n\t\t\t.set({\n\t\t\t\tname: nextName,\n\t\t\t\tpinned_fingerprint: nextFingerprint || existing.pinned_fingerprint || null,\n\t\t\t\tpublic_key: nextPublicKey || existing.public_key || null,\n\t\t\t\taddresses_json: addressesJson,\n\t\t\t\tlast_seen_at: now,\n\t\t\t})\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, input.peerDeviceId))\n\t\t\t.run();\n\t\treturn {\n\t\t\tok: true as const,\n\t\t\tpeer_device_id: input.peerDeviceId,\n\t\t\tcreated: false,\n\t\t\tupdated: true,\n\t\t\tname: nextName,\n\t\t};\n\t})();\n\treturn result;\n}\n\nfunction filterOpsForPeer(\n\tstore: MemoryStore,\n\tpeerDeviceId: string,\n\tops: ReplicationOp[],\n): { allowed: ReplicationOp[]; skipped: number } {\n\tconst filters = readPeerProjectFilters(store, peerDeviceId);\n\tconst allowPrivate = peerClaimedLocalActor(store, peerDeviceId);\n\tconst allowed: ReplicationOp[] = [];\n\tlet skipped = 0;\n\tfor (const op of ops) {\n\t\tif (op.entity_type !== \"memory_item\") {\n\t\t\tallowed.push(op);\n\t\t\tcontinue;\n\t\t}\n\t\tconst payload = parseOpPayload(op);\n\t\tif (!allowPrivate && !syncVisibilityAllowed(payload)) {\n\t\t\tskipped++;\n\t\t\tcontinue;\n\t\t}\n\t\tconst project = payload && typeof payload.project === \"string\" ? payload.project : null;\n\t\tif (!syncProjectAllowedByFilters(project, filters)) {\n\t\t\tskipped++;\n\t\t\tcontinue;\n\t\t}\n\t\tallowed.push(op);\n\t}\n\treturn { allowed, skipped };\n}\n\n// ---------------------------------------------------------------------------\n// Peer row mapping — deduplicated helper (fix #4)\n// ---------------------------------------------------------------------------\n\n/**\n * Map a raw sync_peers DB row to the API response shape.\n * When showDiag is false, sensitive fields (fingerprint, last_error, addresses)\n * are redacted.\n */\nfunction mapPeerRow(\n\tstore: MemoryStore,\n\trow: Record<string, unknown>,\n\tshowDiag: boolean,\n): Record<string, unknown> {\n\treturn {\n\t\tpeer_device_id: row.peer_device_id,\n\t\tname: row.name,\n\t\tfingerprint: showDiag ? row.pinned_fingerprint : null,\n\t\tpinned: Boolean(row.pinned_fingerprint),\n\t\taddresses: showDiag ? safeJsonList(row.addresses_json as string | null) : [],\n\t\tlast_seen_at: row.last_seen_at,\n\t\tlast_sync_at: row.last_sync_at,\n\t\tlast_error: showDiag ? row.last_error : null,\n\t\thas_error: Boolean(row.last_error),\n\t\tclaimed_local_actor: Boolean(row.claimed_local_actor),\n\t\tactor_id: row.actor_id ?? null,\n\t\tactor_display_name: row.actor_display_name ?? null,\n\t\tproject_scope: {\n\t\t\t...currentProjectScope(row, readPeerProjectFilters(store, String(row.peer_device_id ?? \"\"))),\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Peer status helpers\n// ---------------------------------------------------------------------------\n\nfunction isRecentIso(value: unknown, windowS = SYNC_STALE_AFTER_SECONDS): boolean {\n\tconst raw = String(value ?? \"\").trim();\n\tif (!raw) return false;\n\tconst normalized = raw.replace(\"Z\", \"+00:00\");\n\tconst hasOffset = /(?:Z|[+-]\\d{2}:?\\d{2})$/i.test(raw);\n\tconst ts = new Date(hasOffset ? normalized : `${normalized}+00:00`);\n\tif (Number.isNaN(ts.getTime())) return false;\n\tconst ageS = (Date.now() - ts.getTime()) / 1000;\n\treturn ageS >= 0 && ageS <= windowS;\n}\n\nfunction peerStatus(peer: Record<string, unknown>): Record<string, unknown> {\n\tconst lastSyncAt = peer.last_sync_at;\n\tconst lastPingAt = peer.last_seen_at;\n\tconst hasError = Boolean(peer.has_error);\n\n\tconst syncFresh = isRecentIso(lastSyncAt);\n\tconst pingFresh = isRecentIso(lastPingAt);\n\n\tlet peerState: string;\n\tif (hasError && !(syncFresh || pingFresh)) peerState = \"offline\";\n\telse if (hasError) peerState = \"degraded\";\n\telse if (syncFresh || pingFresh) peerState = \"online\";\n\telse if (lastSyncAt || lastPingAt) peerState = \"stale\";\n\telse peerState = \"unknown\";\n\n\tconst syncStatus = hasError ? \"error\" : syncFresh ? \"ok\" : lastSyncAt ? \"stale\" : \"unknown\";\n\tconst pingStatus = pingFresh ? \"ok\" : lastPingAt ? \"stale\" : \"unknown\";\n\n\treturn {\n\t\tsync_status: syncStatus,\n\t\tping_status: pingStatus,\n\t\tpeer_state: peerState,\n\t\tfresh: syncFresh || pingFresh,\n\t\tlast_sync_at: lastSyncAt,\n\t\tlast_ping_at: lastPingAt,\n\t};\n}\n\nfunction attemptStatus(attempt: Record<string, unknown>): string {\n\tif (attempt.ok) return \"ok\";\n\tif (attempt.error) return \"error\";\n\treturn \"unknown\";\n}\n\nfunction readViewerBinding(dbPath: string): { host: string; port: number } | null {\n\ttry {\n\t\tconst raw = readFileSync(join(dirname(dbPath), \"viewer.pid\"), \"utf8\");\n\t\tconst parsed = JSON.parse(raw) as Partial<{ host: string; port: number }>;\n\t\tif (typeof parsed.host === \"string\" && typeof parsed.port === \"number\") {\n\t\t\treturn { host: parsed.host, port: parsed.port };\n\t\t}\n\t} catch {\n\t\t// ignore missing/malformed pidfile\n\t}\n\treturn null;\n}\n\nasync function portOpen(host: string, port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst socket = net.createConnection({ host, port });\n\t\tconst done = (ok: boolean) => {\n\t\t\tsocket.removeAllListeners();\n\t\t\tsocket.destroy();\n\t\t\tresolve(ok);\n\t\t};\n\t\tsocket.setTimeout(300);\n\t\tsocket.once(\"connect\", () => done(true));\n\t\tsocket.once(\"timeout\", () => done(false));\n\t\tsocket.once(\"error\", () => done(false));\n\t});\n}\n\nconst PEERS_QUERY = `\n\tSELECT p.peer_device_id, p.name, p.pinned_fingerprint, p.addresses_json,\n\t p.last_seen_at, p.last_sync_at, p.last_error,\n\t p.projects_include_json, p.projects_exclude_json, p.claimed_local_actor,\n\t p.actor_id, a.display_name AS actor_display_name\n\tFROM sync_peers AS p\n\tLEFT JOIN actors AS a ON a.actor_id = p.actor_id\n\tORDER BY name, peer_device_id\n`;\n\n// ---------------------------------------------------------------------------\n// Route factory\n// ---------------------------------------------------------------------------\n\n/**\n * Peer-to-peer sync protocol routes (/v1/*).\n *\n * These are mounted on the sync listener (0.0.0.0:7337) and are\n * network-accessible. All requests are auth-gated via signature\n * verification so unauthenticated callers are rejected.\n */\nexport function syncProtocolRoutes(getStore: StoreFactory, opts: SyncProtocolRouteOptions = {}) {\n\tconst app = new Hono();\n\tconst routeRateLimit = opts.routeRateLimit ?? null;\n\n\tfunction rateLimitedResponse(c: Context, key: string, authenticated: boolean) {\n\t\tif (!routeRateLimit) return null;\n\t\tconst isRead = c.req.method === \"GET\" || c.req.method === \"HEAD\" || c.req.method === \"OPTIONS\";\n\t\tconst result = routeRateLimit.limiter.check(\n\t\t\t`${c.req.method}:${authenticated ? \"auth\" : \"anon\"}:${key}`,\n\t\t\tauthenticated\n\t\t\t\t? isRead\n\t\t\t\t\t? routeRateLimit.readLimit\n\t\t\t\t\t: routeRateLimit.mutationLimit\n\t\t\t\t: isRead\n\t\t\t\t\t? routeRateLimit.unauthenticatedReadLimit\n\t\t\t\t\t: routeRateLimit.unauthenticatedMutationLimit,\n\t\t);\n\t\tif (result.allowed) return null;\n\t\tc.header(\"Retry-After\", String(result.retryAfterS));\n\t\treturn c.json({ error: \"rate_limited\", retry_after_s: result.retryAfterS }, 429);\n\t}\n\n\t// GET /v1/status (peer sync protocol)\n\tapp.get(\"/v1/status\", (c) => {\n\t\tconst store = getStore();\n\t\treturn (async () => {\n\t\t\tlet auth = authorizeSyncRequest(store, c.req, Buffer.alloc(0));\n\t\t\tlet preauthChecked = false;\n\t\t\tlet bootstrapAttempted = false;\n\t\t\tif (!auth.ok) {\n\t\t\t\tconst bootstrapGrantId = (c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim();\n\t\t\t\tif (bootstrapGrantId) {\n\t\t\t\t\tpreauthChecked = true;\n\t\t\t\t\t// Use unauthenticated bucket with stable key — grant is not yet verified,\n\t\t\t\t\t// so caller-controlled headers must not influence rate-limit identity.\n\t\t\t\t\tconst bootstrapLimited = rateLimitedResponse(c, c.req.path, false);\n\t\t\t\t\tif (bootstrapLimited) return bootstrapLimited;\n\t\t\t\t} else {\n\t\t\t\t\tpreauthChecked = true;\n\t\t\t\t\tconst unauthLimited = rateLimitedResponse(c, c.req.path, false);\n\t\t\t\t\tif (unauthLimited) return unauthLimited;\n\t\t\t\t}\n\t\t\t\tauth = await authorizeBootstrapGrantRequest(store, c.req, Buffer.alloc(0));\n\t\t\t\tbootstrapAttempted = true;\n\t\t\t}\n\t\t\tif (!auth.ok) {\n\t\t\t\t// Specific reasons are logged server-side; wire responses use a generic\n\t\t\t\t// reason to prevent info-disclosure.\n\t\t\t\tif (bootstrapAttempted) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sync] bootstrap grant auth failed: reason=${auth.reason} grant=${(c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim()} path=${c.req.path}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst wireReason = bootstrapAttempted ? \"bootstrap_grant_invalid\" : auth.reason;\n\t\t\t\treturn (\n\t\t\t\t\t(preauthChecked ? null : rateLimitedResponse(c, c.req.path, false)) ??\n\t\t\t\t\tc.json(unauthorizedPayload(wireReason), 401)\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst limited = rateLimitedResponse(c, auth.deviceId, true);\n\t\t\tif (limited) return limited;\n\n\t\t\ttry {\n\t\t\t\tconst [deviceId, fingerprint] = ensureDeviceIdentity(store.db, {\n\t\t\t\t\tkeysDir: syncKeysDir(),\n\t\t\t\t});\n\t\t\t\tconst syncReset = getSyncResetState(store.db);\n\t\t\t\treturn c.json({\n\t\t\t\t\tdevice_id: deviceId,\n\t\t\t\t\tprotocol_version: SYNC_PROTOCOL_VERSION,\n\t\t\t\t\tfingerprint,\n\t\t\t\t\tsync_reset: syncReset,\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\treturn c.json({ error: \"internal_error\" }, 500);\n\t\t\t}\n\t\t})();\n\t});\n\n\t// GET /v1/ops (peer sync protocol)\n\tapp.get(\"/v1/ops\", (c) => {\n\t\tconst store = getStore();\n\t\tconst auth = authorizeSyncRequest(store, c.req, Buffer.alloc(0));\n\t\tif (!auth.ok)\n\t\t\treturn (\n\t\t\t\trateLimitedResponse(c, c.req.path, false) ?? c.json(unauthorizedPayload(auth.reason), 401)\n\t\t\t);\n\t\tconst limited = rateLimitedResponse(c, auth.deviceId, true);\n\t\tif (limited) return limited;\n\t\tconst peerDeviceId = auth.deviceId;\n\n\t\ttry {\n\t\t\tconst since = c.req.query(\"since\") ?? null;\n\t\t\tconst rawLimit = Number.parseInt(c.req.query(\"limit\") ?? \"200\", 10);\n\t\t\tconst rawGeneration = c.req.query(\"generation\");\n\t\t\tconst generation =\n\t\t\t\trawGeneration != null && rawGeneration.trim().length > 0\n\t\t\t\t\t? Number.parseInt(rawGeneration, 10)\n\t\t\t\t\t: null;\n\t\t\tconst snapshotId = c.req.query(\"snapshot_id\") ?? null;\n\t\t\tconst baselineCursor = c.req.query(\"baseline_cursor\") ?? null;\n\t\t\tconst limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(rawLimit, 1000)) : 200;\n\t\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\tconst result = loadReplicationOpsForPeer(store.db, {\n\t\t\t\tsince,\n\t\t\t\tlimit,\n\t\t\t\tdeviceId: localDeviceId,\n\t\t\t\tgeneration: Number.isFinite(generation) ? generation : null,\n\t\t\t\tsnapshotId,\n\t\t\t\tbaselineCursor,\n\t\t\t});\n\t\t\tif (result.reset_required) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"reset_required\",\n\t\t\t\t\t\t...result.reset,\n\t\t\t\t\t},\n\t\t\t\t\t409,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst { ops, nextCursor, boundary } = result;\n\t\t\tconst filtered = filterOpsForPeer(store, peerDeviceId, ops);\n\t\t\treturn c.json({\n\t\t\t\treset_required: false,\n\t\t\t\tgeneration: boundary.generation,\n\t\t\t\tsnapshot_id: boundary.snapshot_id,\n\t\t\t\tbaseline_cursor: boundary.baseline_cursor,\n\t\t\t\tretained_floor_cursor: boundary.retained_floor_cursor,\n\t\t\t\tops: filtered.allowed,\n\t\t\t\tnext_cursor: nextCursor,\n\t\t\t\tskipped: filtered.skipped,\n\t\t\t});\n\t\t} catch {\n\t\t\treturn c.json({ error: \"internal_error\" }, 500);\n\t\t}\n\t});\n\n\t// GET /v1/snapshot (peer sync protocol — bootstrap snapshot pages)\n\tapp.get(\"/v1/snapshot\", (c) => {\n\t\tconst store = getStore();\n\t\treturn (async () => {\n\t\t\tlet auth = authorizeSyncRequest(store, c.req, Buffer.alloc(0));\n\t\t\tlet preauthChecked = false;\n\t\t\tlet bootstrapAttempted = false;\n\t\t\tif (!auth.ok) {\n\t\t\t\tconst bootstrapGrantId = (c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim();\n\t\t\t\tif (bootstrapGrantId) {\n\t\t\t\t\tpreauthChecked = true;\n\t\t\t\t\t// Use unauthenticated bucket with stable key — grant is not yet verified,\n\t\t\t\t\t// so caller-controlled headers must not influence rate-limit identity.\n\t\t\t\t\tconst bootstrapLimited = rateLimitedResponse(c, c.req.path, false);\n\t\t\t\t\tif (bootstrapLimited) return bootstrapLimited;\n\t\t\t\t} else {\n\t\t\t\t\tpreauthChecked = true;\n\t\t\t\t\tconst unauthLimited = rateLimitedResponse(c, c.req.path, false);\n\t\t\t\t\tif (unauthLimited) return unauthLimited;\n\t\t\t\t}\n\t\t\t\tauth = await authorizeBootstrapGrantRequest(store, c.req, Buffer.alloc(0));\n\t\t\t\tbootstrapAttempted = true;\n\t\t\t}\n\t\t\tif (!auth.ok) {\n\t\t\t\t// Specific reasons are logged server-side; wire responses use a generic\n\t\t\t\t// reason to prevent info-disclosure.\n\t\t\t\tif (bootstrapAttempted) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sync] bootstrap grant auth failed: reason=${auth.reason} grant=${(c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim()} path=${c.req.path}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst wireReason = bootstrapAttempted ? \"bootstrap_grant_invalid\" : auth.reason;\n\t\t\t\treturn (\n\t\t\t\t\t(preauthChecked ? null : rateLimitedResponse(c, c.req.path, false)) ??\n\t\t\t\t\tc.json(unauthorizedPayload(wireReason), 401)\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst limited = rateLimitedResponse(c, auth.deviceId, true);\n\t\t\tif (limited) return limited;\n\n\t\t\ttry {\n\t\t\t\tconst rawGeneration = c.req.query(\"generation\");\n\t\t\t\tconst generation =\n\t\t\t\t\trawGeneration != null && rawGeneration.trim().length > 0\n\t\t\t\t\t\t? Number.parseInt(rawGeneration, 10)\n\t\t\t\t\t\t: null;\n\t\t\t\tconst snapshotId = c.req.query(\"snapshot_id\") ?? null;\n\t\t\t\tconst baselineCursor = c.req.query(\"baseline_cursor\") ?? null;\n\t\t\t\tconst pageToken = c.req.query(\"page_token\") ?? null;\n\t\t\t\tconst rawLimit = Number.parseInt(c.req.query(\"limit\") ?? \"200\", 10);\n\t\t\t\t// Cap raised to 5000 to support elevated bootstrap page sizes (default 2000).\n\t\t\t\tconst limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(rawLimit, 5000)) : 200;\n\n\t\t\t\tif (generation == null || !Number.isFinite(generation)) {\n\t\t\t\t\treturn c.json({ error: \"missing_generation\" }, 400);\n\t\t\t\t}\n\t\t\t\tif (!snapshotId) {\n\t\t\t\t\treturn c.json({ error: \"missing_snapshot_id\" }, 400);\n\t\t\t\t}\n\n\t\t\t\tconst result = loadMemorySnapshotPageForPeer(store.db, {\n\t\t\t\t\tgeneration,\n\t\t\t\t\tsnapshotId,\n\t\t\t\t\tbaselineCursor,\n\t\t\t\t\tpageToken,\n\t\t\t\t\tlimit,\n\t\t\t\t\tpeerDeviceId: auth.deviceId,\n\t\t\t\t});\n\n\t\t\t\treturn c.json({\n\t\t\t\t\tgeneration: result.boundary.generation,\n\t\t\t\t\tsnapshot_id: result.boundary.snapshot_id,\n\t\t\t\t\tbaseline_cursor: result.boundary.baseline_cursor,\n\t\t\t\t\tretained_floor_cursor: result.boundary.retained_floor_cursor,\n\t\t\t\t\titems: result.items,\n\t\t\t\t\tnext_page_token: result.nextPageToken,\n\t\t\t\t\thas_more: result.hasMore,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"\";\n\t\t\t\tif (message === \"generation_mismatch\" || message === \"boundary_mismatch\") {\n\t\t\t\t\treturn c.json({ error: message }, 409);\n\t\t\t\t}\n\t\t\t\treturn c.json({ error: \"internal_error\" }, 500);\n\t\t\t}\n\t\t})();\n\t});\n\n\t// POST /v1/ops (peer sync protocol)\n\tapp.post(\"/v1/ops\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst raw = await readBoundedRequestBytes(c.req.raw, MAX_SYNC_BODY_BYTES);\n\t\tif (raw == null) {\n\t\t\treturn c.json({ error: \"payload_too_large\" }, 413);\n\t\t}\n\n\t\tconst auth = authorizeSyncRequest(store, c.req, raw);\n\t\tif (!auth.ok)\n\t\t\treturn (\n\t\t\t\trateLimitedResponse(c, c.req.path, false) ?? c.json(unauthorizedPayload(auth.reason), 401)\n\t\t\t);\n\t\tconst limited = rateLimitedResponse(c, auth.deviceId, true);\n\t\tif (limited) return limited;\n\t\tconst peerDeviceId = auth.deviceId;\n\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(raw.toString(\"utf-8\")) as unknown;\n\t\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\t\t\treturn c.json({ error: \"invalid_json\" }, 400);\n\t\t\t}\n\t\t\tbody = parsed as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid_json\" }, 400);\n\t\t}\n\n\t\tif (!Array.isArray(body.ops)) {\n\t\t\treturn c.json({ error: \"invalid_ops\" }, 400);\n\t\t}\n\t\tif (body.ops.length > MAX_SYNC_OPS) {\n\t\t\treturn c.json({ error: \"too_many_ops\" }, 413);\n\t\t}\n\n\t\tconst normalizedOps = extractReplicationOps(body);\n\t\tfor (const op of normalizedOps) {\n\t\t\tif (op.device_id !== peerDeviceId || op.clock_device_id !== peerDeviceId) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"invalid_op_device\",\n\t\t\t\t\t\treason: \"device_id_mismatch\",\n\t\t\t\t\t\top_id: op.op_id,\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\n\t\tconst filteredInbound = filterOpsForPeer(store, peerDeviceId, normalizedOps);\n\t\tconst result = applyReplicationOps(store.db, filteredInbound.allowed, localDeviceId);\n\t\treturn c.json({\n\t\t\t...result,\n\t\t\tskipped: result.skipped + filteredInbound.skipped,\n\t\t});\n\t});\n\n\treturn app;\n}\n\n/**\n * Viewer-facing sync management routes (/api/sync/*).\n *\n * These are mounted on the viewer listener (127.0.0.1:38888) and\n * provide sync status, peer management, and coordinator UI for the\n * local viewer.\n */\nexport function syncRoutes(\n\tgetStore: StoreFactory,\n\tgetSyncRuntimeStatus?: () => SyncRuntimeStatus | null,\n) {\n\tconst app = new Hono();\n\n\t// GET /api/sync/status\n\tapp.get(\"/api/sync/status\", async (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst traceSync = <T>(label: string, fn: () => T): T => {\n\t\t\t\tif (process.env.CODEMEM_TRACE_SYNC_STATUS !== \"1\") return fn();\n\t\t\t\tconst startedAt = Date.now();\n\t\t\t\tconsole.warn(`[codemem sync-status] ${label} start`);\n\t\t\t\ttry {\n\t\t\t\t\treturn fn();\n\t\t\t\t} finally {\n\t\t\t\t\tconsole.warn(`[codemem sync-status] ${label} ${Date.now() - startedAt}ms`);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst showDiag = queryBool(c.req.query(\"includeDiagnostics\"));\n\t\t\tconst includeJoinRequests = queryBool(c.req.query(\"includeJoinRequests\"));\n\t\t\tconst project = c.req.query(\"project\") || null;\n\t\t\tconst config = traceSync(\"readCoordinatorSyncConfig\", () => readCoordinatorSyncConfig());\n\t\t\tconst syncReset = traceSync(\"getSyncResetState\", () => getSyncResetState(store.db));\n\n\t\t\tconst d = drizzle(store.db, { schema });\n\n\t\t\tconst deviceRow = traceSync(\"deviceRow\", () =>\n\t\t\t\td\n\t\t\t\t\t.select({\n\t\t\t\t\t\tdevice_id: schema.syncDevice.device_id,\n\t\t\t\t\t\tfingerprint: schema.syncDevice.fingerprint,\n\t\t\t\t\t})\n\t\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t\t.limit(1)\n\t\t\t\t\t.get(),\n\t\t\t);\n\n\t\t\tconst daemonState = traceSync(\"daemonState\", () =>\n\t\t\t\td.select().from(schema.syncDaemonState).where(eq(schema.syncDaemonState.id, 1)).get(),\n\t\t\t);\n\n\t\t\tconst peerCountRow = traceSync(\"peerCountRow\", () =>\n\t\t\t\td.select({ total: count() }).from(schema.syncPeers).get(),\n\t\t\t);\n\t\t\tlet retentionState:\n\t\t\t\t| {\n\t\t\t\t\t\tlast_run_at?: string | null;\n\t\t\t\t\t\tlast_duration_ms?: number | null;\n\t\t\t\t\t\tlast_deleted_ops?: number | null;\n\t\t\t\t\t\tlast_estimated_bytes_before?: number | null;\n\t\t\t\t\t\tlast_estimated_bytes_after?: number | null;\n\t\t\t\t\t\tretained_floor_cursor?: string | null;\n\t\t\t\t\t\tlast_error?: string | null;\n\t\t\t\t\t\tlast_error_at?: string | null;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\ttry {\n\t\t\t\tretentionState = traceSync(\"retentionState\", () =>\n\t\t\t\t\td\n\t\t\t\t\t\t.select()\n\t\t\t\t\t\t.from(schema.syncRetentionState)\n\t\t\t\t\t\t.where(eq(schema.syncRetentionState.id, 1))\n\t\t\t\t\t\t.get(),\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\tretentionState = undefined;\n\t\t\t}\n\n\t\t\tconst lastSyncRow = traceSync(\"lastSyncRow\", () =>\n\t\t\t\td\n\t\t\t\t\t.select({ last_sync_at: max(schema.syncPeers.last_sync_at) })\n\t\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t\t.get(),\n\t\t\t);\n\t\t\tconst semanticIndex = traceSync(\"semanticIndex\", () =>\n\t\t\t\tredactSemanticIndexDiagnostics(\n\t\t\t\t\tgetSemanticIndexDiagnostics(store.db, { fastCounts: !showDiag }),\n\t\t\t\t\tshowDiag,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst lastError = daemonState?.last_error as string | null;\n\t\t\tconst lastErrorAt = daemonState?.last_error_at as string | null;\n\t\t\tconst lastOkAt = daemonState?.last_ok_at as string | null;\n\t\t\tconst viewerBinding = traceSync(\"readViewerBinding\", () => readViewerBinding(store.dbPath));\n\t\t\tconst daemonRunning = viewerBinding\n\t\t\t\t? await portOpen(viewerBinding.host, viewerBinding.port)\n\t\t\t\t: false;\n\t\t\tconst daemonDetail = viewerBinding\n\t\t\t\t? daemonRunning\n\t\t\t\t\t? `viewer pidfile at ${viewerBinding.host}:${viewerBinding.port}`\n\t\t\t\t\t: `pidfile present but ${viewerBinding.host}:${viewerBinding.port} is unreachable`\n\t\t\t\t: null;\n\n\t\t\tlet daemonStateValue = \"ok\";\n\t\t\tif (!config.syncEnabled) {\n\t\t\t\tdaemonStateValue = \"disabled\";\n\t\t\t} else if (lastError && (!lastOkAt || String(lastOkAt) < String(lastErrorAt ?? \"\"))) {\n\t\t\t\tdaemonStateValue = \"error\";\n\t\t\t} else if (!daemonRunning) {\n\t\t\t\tdaemonStateValue = \"stopped\";\n\t\t\t}\n\n\t\t\tconst statusPayload: Record<string, unknown> = {\n\t\t\t\tenabled: config.syncEnabled,\n\t\t\t\tinterval_s: config.syncIntervalS,\n\t\t\t\tretention: {\n\t\t\t\t\tenabled: config.syncRetentionEnabled,\n\t\t\t\t\tmax_age_days: config.syncRetentionMaxAgeDays,\n\t\t\t\t\tmax_size_mb: config.syncRetentionMaxSizeMb,\n\t\t\t\t\tretained_floor_cursor:\n\t\t\t\t\t\tsyncReset.retained_floor_cursor ??\n\t\t\t\t\t\t(retentionState?.retained_floor_cursor as string | null) ??\n\t\t\t\t\t\tnull,\n\t\t\t\t\tlast_run_at: (retentionState?.last_run_at as string | null) ?? null,\n\t\t\t\t\tlast_duration_ms:\n\t\t\t\t\t\ttypeof retentionState?.last_duration_ms === \"number\"\n\t\t\t\t\t\t\t? retentionState.last_duration_ms\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tlast_deleted_ops:\n\t\t\t\t\t\ttypeof retentionState?.last_deleted_ops === \"number\"\n\t\t\t\t\t\t\t? retentionState.last_deleted_ops\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tlast_estimated_bytes_before:\n\t\t\t\t\t\ttypeof retentionState?.last_estimated_bytes_before === \"number\"\n\t\t\t\t\t\t\t? retentionState.last_estimated_bytes_before\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tlast_estimated_bytes_after:\n\t\t\t\t\t\ttypeof retentionState?.last_estimated_bytes_after === \"number\"\n\t\t\t\t\t\t\t? retentionState.last_estimated_bytes_after\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tlast_error: (retentionState?.last_error as string | null) ?? null,\n\t\t\t\t\tlast_error_at: (retentionState?.last_error_at as string | null) ?? null,\n\t\t\t\t},\n\t\t\t\tsemantic_index: semanticIndex,\n\t\t\t\tpeer_count: Number(peerCountRow?.total ?? 0),\n\t\t\t\tlast_sync_at: lastSyncRow?.last_sync_at ?? null,\n\t\t\t\tdaemon_state: daemonStateValue,\n\t\t\t\tdaemon_running: daemonRunning,\n\t\t\t\tdaemon_detail: daemonDetail,\n\t\t\t\tproject_filter_active:\n\t\t\t\t\tconfig.syncProjectsInclude.length > 0 || config.syncProjectsExclude.length > 0,\n\t\t\t\tproject_filter: {\n\t\t\t\t\tinclude: config.syncProjectsInclude,\n\t\t\t\t\texclude: config.syncProjectsExclude,\n\t\t\t\t},\n\t\t\t\tredacted: !showDiag,\n\t\t\t};\n\n\t\t\tif (showDiag) {\n\t\t\t\tstatusPayload.device_id = deviceRow?.device_id ?? null;\n\t\t\t\tstatusPayload.fingerprint = deviceRow?.fingerprint ?? null;\n\t\t\t\tstatusPayload.bind = `${config.syncHost}:${config.syncPort}`;\n\t\t\t\tstatusPayload.daemon_last_error = lastError;\n\t\t\t\tstatusPayload.daemon_last_error_at = lastErrorAt;\n\t\t\t\tstatusPayload.daemon_last_ok_at = lastOkAt;\n\t\t\t}\n\n\t\t\tconst runtimeStatus = getSyncRuntimeStatus?.() ?? null;\n\t\t\tif (runtimeStatus?.phase && runtimeStatus.phase !== \"running\") {\n\t\t\t\tdaemonStateValue = runtimeStatus.phase;\n\t\t\t\tstatusPayload.daemon_state = daemonStateValue;\n\t\t\t\tstatusPayload.daemon_running = runtimeStatus.phase === \"starting\" || daemonRunning;\n\t\t\t\tstatusPayload.daemon_detail = runtimeStatus.detail ?? daemonDetail;\n\t\t\t}\n\n\t\t\t// Build peers list using deduplicated mapPeerRow\n\t\t\tconst peerRows = traceSync(\n\t\t\t\t\"peerRows\",\n\t\t\t\t() => store.db.prepare(PEERS_QUERY).all() as Record<string, unknown>[],\n\t\t\t);\n\t\t\tconst peersItems = peerRows.map((row) => {\n\t\t\t\tconst peer = mapPeerRow(store, row, showDiag);\n\t\t\t\tpeer.status = peerStatus(peer);\n\t\t\t\treturn peer;\n\t\t\t});\n\n\t\t\tconst peersMap: Record<string, unknown> = {};\n\t\t\tfor (const peer of peersItems) {\n\t\t\t\tpeersMap[String(peer.peer_device_id)] = peer.status;\n\t\t\t}\n\n\t\t\t// Attempts\n\t\t\tconst attemptRows = traceSync(\"attemptRows\", () =>\n\t\t\t\td\n\t\t\t\t\t.select({\n\t\t\t\t\t\tpeer_device_id: schema.syncAttempts.peer_device_id,\n\t\t\t\t\t\tok: schema.syncAttempts.ok,\n\t\t\t\t\t\terror: schema.syncAttempts.error,\n\t\t\t\t\t\tstarted_at: schema.syncAttempts.started_at,\n\t\t\t\t\t\tfinished_at: schema.syncAttempts.finished_at,\n\t\t\t\t\t\tops_in: schema.syncAttempts.ops_in,\n\t\t\t\t\t\tops_out: schema.syncAttempts.ops_out,\n\t\t\t\t\t})\n\t\t\t\t\t.from(schema.syncAttempts)\n\t\t\t\t\t.orderBy(desc(schema.syncAttempts.finished_at))\n\t\t\t\t\t.limit(25)\n\t\t\t\t\t.all(),\n\t\t\t);\n\t\t\tconst peerAddressMap = new Map<string, string[]>();\n\t\t\tconst peerAddressRows = traceSync(\n\t\t\t\t\"peerAddressRows\",\n\t\t\t\t() =>\n\t\t\t\t\tstore.db.prepare(\"SELECT peer_device_id, addresses_json FROM sync_peers\").all() as Array<{\n\t\t\t\t\t\tpeer_device_id: string | null;\n\t\t\t\t\t\taddresses_json: string | null;\n\t\t\t\t\t}>,\n\t\t\t);\n\t\t\tpeerAddressRows.forEach((peerRow) => {\n\t\t\t\tconst addrs = safeJsonList(peerRow.addresses_json as string | null);\n\t\t\t\tif (addrs.length) peerAddressMap.set(String(peerRow.peer_device_id ?? \"\"), addrs);\n\t\t\t});\n\t\t\tconst attemptsItems = attemptRows.map((row) => {\n\t\t\t\tconst addrs = showDiag ? peerAddressMap.get(String(row.peer_device_id ?? \"\")) : undefined;\n\t\t\t\treturn {\n\t\t\t\t\t...row,\n\t\t\t\t\tstatus: attemptStatus(row),\n\t\t\t\t\taddress: addrs?.length ? addrs[0] : null,\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst latestAttemptError = String(attemptsItems[0]?.error || \"\").trim();\n\n\t\t\tconst statusBlock: Record<string, unknown> = {\n\t\t\t\t...statusPayload,\n\t\t\t\tbackground_maintenance: summarizeMaintenanceJobs(listMaintenanceJobs(store.db), showDiag),\n\t\t\t\tpeers: peersMap,\n\t\t\t\tpending: 0,\n\t\t\t\tsync: {},\n\t\t\t\tping: {},\n\t\t\t};\n\t\t\tconst legacyDevices = traceSync(\"legacyDevices\", () => store.claimableLegacyDeviceIds());\n\t\t\tconst sharingReview = traceSync(\"sharingReview\", () => store.sharingReviewSummary(project));\n\t\t\tconst coordinatorSnapshot = await coordinatorStatusSnapshot(store, config);\n\t\t\tconst coordinator = traceSync(\"coordinator\", () =>\n\t\t\t\tredactCoordinatorStatus(coordinatorSnapshot, showDiag),\n\t\t\t);\n\t\t\tlet joinRequests: Record<string, unknown>[] = [];\n\t\t\tif (includeJoinRequests && showDiag && config.syncCoordinatorAdminSecret) {\n\t\t\t\ttry {\n\t\t\t\t\tjoinRequests = await listCoordinatorJoinRequests(config);\n\t\t\t\t} catch {\n\t\t\t\t\tjoinRequests = [];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (daemonStateValue === \"ok\" && latestAttemptError.startsWith(\"needs_attention:\")) {\n\t\t\t\tdaemonStateValue = \"needs_attention\";\n\t\t\t\tstatusPayload.daemon_state = daemonStateValue;\n\t\t\t\tstatusPayload.daemon_detail = latestAttemptError.replace(/^needs_attention:/, \"\");\n\t\t\t\tstatusBlock.daemon_state = daemonStateValue;\n\t\t\t\tstatusBlock.daemon_detail = latestAttemptError.replace(/^needs_attention:/, \"\");\n\t\t\t}\n\n\t\t\tif (daemonStateValue === \"ok\") {\n\t\t\t\tconst peerStates = new Set(\n\t\t\t\t\tpeersItems.map((peer) =>\n\t\t\t\t\t\tString((peer.status as Record<string, unknown> | undefined)?.peer_state ?? \"\"),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tconst latestFailedRecently = Boolean(\n\t\t\t\t\tattemptsItems[0] &&\n\t\t\t\t\t\tattemptsItems[0].status === \"error\" &&\n\t\t\t\t\t\tisRecentIso(attemptsItems[0].finished_at),\n\t\t\t\t);\n\t\t\t\tconst allOffline =\n\t\t\t\t\tpeersItems.length > 0 &&\n\t\t\t\t\tpeersItems.every(\n\t\t\t\t\t\t(peer) =>\n\t\t\t\t\t\t\tString((peer.status as Record<string, unknown>)?.peer_state ?? \"\") === \"offline\",\n\t\t\t\t\t);\n\t\t\t\tif (latestFailedRecently) {\n\t\t\t\t\tconst hasLivePeer = peerStates.has(\"online\") || peerStates.has(\"degraded\");\n\t\t\t\t\tif (hasLivePeer) daemonStateValue = \"degraded\";\n\t\t\t\t\telse if (allOffline) daemonStateValue = \"offline-peers\";\n\t\t\t\t\telse if (peersItems.length > 0) daemonStateValue = \"stale\";\n\t\t\t\t} else if (peerStates.has(\"degraded\")) {\n\t\t\t\t\tdaemonStateValue = \"degraded\";\n\t\t\t\t} else if (allOffline) {\n\t\t\t\t\tdaemonStateValue = \"offline-peers\";\n\t\t\t\t} else if (peersItems.length > 0 && !peerStates.has(\"online\")) {\n\t\t\t\t\tdaemonStateValue = \"stale\";\n\t\t\t\t}\n\t\t\t\tstatusPayload.daemon_state = daemonStateValue;\n\t\t\t\tstatusBlock.daemon_state = daemonStateValue;\n\t\t\t}\n\n\t\t\tconst responsePayload: Record<string, unknown> = {\n\t\t\t\t...statusPayload,\n\t\t\t\tstatus: statusBlock,\n\t\t\t\tpeers: peersItems,\n\t\t\t\tattempts: attemptsItems.slice(0, 5),\n\t\t\t\tlegacy_devices: legacyDevices,\n\t\t\t\tsharing_review: sharingReview,\n\t\t\t\tcoordinator,\n\t\t\t};\n\t\t\tif (includeJoinRequests && showDiag) {\n\t\t\t\tresponsePayload.join_requests = joinRequests;\n\t\t\t}\n\t\t\treturn c.json(responsePayload);\n\t\t}\n\t});\n\n\t// GET /api/sync/peers\n\tapp.get(\"/api/sync/peers\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst showDiag = queryBool(c.req.query(\"includeDiagnostics\"));\n\t\t\tconst rows = store.db.prepare(PEERS_QUERY).all() as Record<string, unknown>[];\n\t\t\t// Use deduplicated mapPeerRow helper (fix #4)\n\t\t\tconst peers = rows.map((row) => mapPeerRow(store, row, showDiag));\n\t\t\treturn c.json({ items: peers, redacted: !showDiag });\n\t\t}\n\t});\n\n\t// GET /api/sync/actors\n\tapp.get(\"/api/sync/actors\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tensureLocalActorRecord(store);\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst includeMerged = queryBool(c.req.query(\"includeMerged\"));\n\t\t\tconst query = d.select().from(schema.actors);\n\t\t\tconst rows = includeMerged\n\t\t\t\t? query.orderBy(schema.actors.display_name).all()\n\t\t\t\t: query\n\t\t\t\t\t\t.where(and(ne(schema.actors.status, \"merged\"), ne(schema.actors.status, \"deactivated\")))\n\t\t\t\t\t\t.orderBy(schema.actors.display_name)\n\t\t\t\t\t\t.all();\n\t\t\treturn c.json({ items: rows });\n\t\t}\n\t});\n\n\t// GET /api/sync/attempts\n\tapp.get(\"/api/sync/attempts\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tlet limit = queryInt(c.req.query(\"limit\"), 25);\n\t\t\tif (limit <= 0) return c.json({ error: \"invalid_limit\" }, 400);\n\t\t\tlimit = Math.min(limit, 500);\n\t\t\tconst rows = d\n\t\t\t\t.select({\n\t\t\t\t\tpeer_device_id: schema.syncAttempts.peer_device_id,\n\t\t\t\t\tok: schema.syncAttempts.ok,\n\t\t\t\t\terror: schema.syncAttempts.error,\n\t\t\t\t\tstarted_at: schema.syncAttempts.started_at,\n\t\t\t\t\tfinished_at: schema.syncAttempts.finished_at,\n\t\t\t\t\tops_in: schema.syncAttempts.ops_in,\n\t\t\t\t\tops_out: schema.syncAttempts.ops_out,\n\t\t\t\t})\n\t\t\t\t.from(schema.syncAttempts)\n\t\t\t\t.orderBy(desc(schema.syncAttempts.finished_at))\n\t\t\t\t.limit(limit)\n\t\t\t\t.all();\n\t\t\treturn c.json({ items: rows });\n\t\t}\n\t});\n\n\t// GET /api/sync/pairing — uses ensureDeviceIdentity from core (fix #5 context)\n\tapp.get(\"/api/sync/pairing\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst showDiag = queryBool(c.req.query(\"includeDiagnostics\"));\n\t\t\tif (!showDiag) {\n\t\t\t\treturn c.json({\n\t\t\t\t\tredacted: true,\n\t\t\t\t\tpairing_filter_hint: PAIRING_FILTER_HINT,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst deviceRow = d\n\t\t\t\t.select({\n\t\t\t\t\tdevice_id: schema.syncDevice.device_id,\n\t\t\t\t\tpublic_key: schema.syncDevice.public_key,\n\t\t\t\t\tfingerprint: schema.syncDevice.fingerprint,\n\t\t\t\t})\n\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t.limit(1)\n\t\t\t\t.get();\n\n\t\t\tlet deviceId: string | undefined;\n\t\t\tlet publicKey: string | undefined;\n\t\t\tlet fingerprint: string | undefined;\n\n\t\t\tif (deviceRow) {\n\t\t\t\tdeviceId = String(deviceRow.device_id);\n\t\t\t\tpublicKey = String(deviceRow.public_key);\n\t\t\t\tfingerprint = String(deviceRow.fingerprint);\n\t\t\t} else {\n\t\t\t\t// Fall back to ensureDeviceIdentity if no row exists\n\t\t\t\ttry {\n\t\t\t\t\tconst [id, fp] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\t\t\tdeviceId = id;\n\t\t\t\t\tfingerprint = fp;\n\t\t\t\t\tconst newRow = d\n\t\t\t\t\t\t.select({ public_key: schema.syncDevice.public_key })\n\t\t\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t\t\t.where(eq(schema.syncDevice.device_id, id))\n\t\t\t\t\t\t.get();\n\t\t\t\t\tpublicKey = newRow?.public_key ?? \"\";\n\t\t\t\t} catch {\n\t\t\t\t\treturn c.json({ error: \"device identity unavailable\" }, 500);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!deviceId || !fingerprint) {\n\t\t\t\treturn c.json({ error: \"public key missing\" }, 500);\n\t\t\t}\n\n\t\t\treturn c.json({\n\t\t\t\tdevice_id: deviceId,\n\t\t\t\tfingerprint,\n\t\t\t\tpublic_key: publicKey ?? null,\n\t\t\t\tpairing_filter_hint: PAIRING_FILTER_HINT,\n\t\t\t\taddresses: [],\n\t\t\t});\n\t\t}\n\t});\n\n\t// ------------------------------------------------------------------\n\t// POST mutations\n\t// ------------------------------------------------------------------\n\n\t// POST /api/sync/peers/rename\n\tapp.post(\"/api/sync/peers/rename\", async (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst body = await c.req.json<Record<string, unknown>>();\n\t\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\t\tconst name = String(body.name ?? \"\").trim();\n\t\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\t\tif (!name) return c.json({ error: \"name required\" }, 400);\n\t\t\tconst exists = d\n\t\t\t\t.select({ peer_device_id: schema.syncPeers.peer_device_id })\n\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t\t.get();\n\t\t\tif (!exists) return c.json({ error: \"peer not found\" }, 404);\n\t\t\td.update(schema.syncPeers)\n\t\t\t\t.set({ name })\n\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t\t.run();\n\t\t\treturn c.json({ ok: true });\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/run\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown> = {};\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\tbody = {};\n\t\t}\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tif (!config.syncEnabled) {\n\t\t\treturn c.json({ error: \"sync_disabled\" }, 403);\n\t\t}\n\t\tconst address =\n\t\t\ttypeof body.address === \"string\" && body.address.trim() ? body.address.trim() : null;\n\t\tconst requestedPeerId =\n\t\t\ttypeof body.peer_device_id === \"string\" && body.peer_device_id.trim()\n\t\t\t\t? body.peer_device_id.trim()\n\t\t\t\t: null;\n\t\tlet peerIds: string[];\n\t\tif (address) {\n\t\t\tconst peerId = findPeerDeviceIdForAddress(store, address);\n\t\t\tif (!peerId) return c.json({ error: \"unknown peer address\" }, 404);\n\t\t\tpeerIds = [peerId];\n\t\t} else if (requestedPeerId) {\n\t\t\tconst requestedPeerRows = store.db\n\t\t\t\t.prepare(\"SELECT peer_device_id FROM sync_peers WHERE peer_device_id = ?\")\n\t\t\t\t.all(requestedPeerId) as Array<{ peer_device_id: string | null }>;\n\t\t\tpeerIds = requestedPeerRows\n\t\t\t\t.map((row) => String(row.peer_device_id ?? \"\").trim())\n\t\t\t\t.filter(Boolean);\n\t\t} else {\n\t\t\tconst allPeerRows = store.db.prepare(\"SELECT peer_device_id FROM sync_peers\").all() as Array<{\n\t\t\t\tpeer_device_id: string | null;\n\t\t\t}>;\n\t\t\tpeerIds = allPeerRows.map((row) => String(row.peer_device_id ?? \"\").trim()).filter(Boolean);\n\t\t}\n\t\tconst items = [] as Array<Record<string, unknown>>;\n\t\tfor (const peerId of peerIds) {\n\t\t\tconst result = await runSyncPass(store.db, peerId);\n\t\t\titems.push({ peer_device_id: peerId, ...result });\n\t\t}\n\t\treturn c.json({ items });\n\t});\n\n\tapp.post(\"/api/sync/peers/scope\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\tconst include = Array.isArray(body.include)\n\t\t\t? body.include\n\t\t\t\t\t.filter((value): value is string => typeof value === \"string\")\n\t\t\t\t\t.map((value) => value.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t: null;\n\t\tconst exclude = Array.isArray(body.exclude)\n\t\t\t? body.exclude\n\t\t\t\t\t.filter((value): value is string => typeof value === \"string\")\n\t\t\t\t\t.map((value) => value.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t: null;\n\t\tconst inheritGlobal = Boolean(body.inherit_global);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst exists = d\n\t\t\t.select({ peer_device_id: schema.syncPeers.peer_device_id })\n\t\t\t.from(schema.syncPeers)\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.get();\n\t\tif (!exists) return c.json({ error: \"peer not found\" }, 404);\n\t\td.update(schema.syncPeers)\n\t\t\t.set({\n\t\t\t\tprojects_include_json: inheritGlobal ? null : JSON.stringify(include ?? []),\n\t\t\t\tprojects_exclude_json: inheritGlobal ? null : JSON.stringify(exclude ?? []),\n\t\t\t})\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.run();\n\t\tconst row = d\n\t\t\t.select({\n\t\t\t\tprojects_include_json: schema.syncPeers.projects_include_json,\n\t\t\t\tprojects_exclude_json: schema.syncPeers.projects_exclude_json,\n\t\t\t})\n\t\t\t.from(schema.syncPeers)\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.get() as Record<string, unknown> | undefined;\n\t\tif (!row) return c.json({ error: \"peer not found\" }, 404);\n\t\treturn c.json({\n\t\t\tok: true,\n\t\t\tproject_scope: currentProjectScope(row, readPeerProjectFilters(store, peerDeviceId)),\n\t\t});\n\t});\n\n\tapp.post(\"/api/sync/peers/identity\", async (c) => {\n\t\tconst store = getStore();\n\t\tensureLocalActorRecord(store);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\tconst requestedActorId =\n\t\t\tbody.actor_id == null ? undefined : String(body.actor_id ?? \"\").trim() || null;\n\t\tconst claimedLocalActor =\n\t\t\ttypeof body.claimed_local_actor === \"boolean\" ? body.claimed_local_actor : undefined;\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst peer = d\n\t\t\t.select({\n\t\t\t\tpeer_device_id: schema.syncPeers.peer_device_id,\n\t\t\t\tactor_id: schema.syncPeers.actor_id,\n\t\t\t\tclaimed_local_actor: schema.syncPeers.claimed_local_actor,\n\t\t\t})\n\t\t\t.from(schema.syncPeers)\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.get();\n\t\tif (!peer) return c.json({ error: \"peer not found\" }, 404);\n\n\t\tlet nextActorId = peer.actor_id ?? null;\n\t\tlet nextClaimedLocalActor = Boolean(peer.claimed_local_actor);\n\t\tif (requestedActorId !== undefined) {\n\t\t\tnextActorId = requestedActorId;\n\t\t\tif (requestedActorId) {\n\t\t\t\tconst actor = d\n\t\t\t\t\t.select({\n\t\t\t\t\t\tactor_id: schema.actors.actor_id,\n\t\t\t\t\t\tis_local: schema.actors.is_local,\n\t\t\t\t\t\tstatus: schema.actors.status,\n\t\t\t\t\t})\n\t\t\t\t\t.from(schema.actors)\n\t\t\t\t\t.where(eq(schema.actors.actor_id, requestedActorId))\n\t\t\t\t\t.get();\n\t\t\t\tif (!actor) return c.json({ error: \"actor not found\" }, 404);\n\t\t\t\tif (actor.status !== \"active\") return c.json({ error: \"actor not active\" }, 409);\n\t\t\t\tnextClaimedLocalActor = claimedLocalActor ?? Boolean(actor.is_local);\n\t\t\t} else {\n\t\t\t\tnextClaimedLocalActor = claimedLocalActor ?? false;\n\t\t\t}\n\t\t} else if (claimedLocalActor !== undefined) {\n\t\t\tnextClaimedLocalActor = claimedLocalActor;\n\t\t\tif (claimedLocalActor) {\n\t\t\t\tnextActorId = store.actorId;\n\t\t\t} else if (nextActorId === store.actorId) {\n\t\t\t\tnextActorId = null;\n\t\t\t}\n\t\t}\n\n\t\td.update(schema.syncPeers)\n\t\t\t.set({\n\t\t\t\tactor_id: nextActorId,\n\t\t\t\tclaimed_local_actor: nextClaimedLocalActor ? 1 : 0,\n\t\t\t})\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.run();\n\t\treturn c.json({ ok: true, actor_id: nextActorId, claimed_local_actor: nextClaimedLocalActor });\n\t});\n\n\tapp.post(\"/api/sync/actors\", async (c) => {\n\t\tconst store = getStore();\n\t\tensureLocalActorRecord(store);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst displayName = String(body.display_name ?? \"\").trim();\n\t\tif (!displayName) return c.json({ error: \"display_name required\" }, 400);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst now = new Date().toISOString();\n\t\tconst actor = {\n\t\t\tactor_id: randomUUID(),\n\t\t\tdisplay_name: displayName,\n\t\t\tis_local: 0,\n\t\t\tstatus: \"active\",\n\t\t\tmerged_into_actor_id: null,\n\t\t\tcreated_at: now,\n\t\t\tupdated_at: now,\n\t\t};\n\t\td.insert(schema.actors).values(actor).run();\n\t\treturn c.json(actor);\n\t});\n\n\tapp.post(\"/api/sync/actors/rename\", async (c) => {\n\t\tconst store = getStore();\n\t\tensureLocalActorRecord(store);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst actorId = String(body.actor_id ?? \"\").trim();\n\t\tconst displayName = String(body.display_name ?? \"\").trim();\n\t\tif (!actorId) return c.json({ error: \"actor_id required\" }, 400);\n\t\tif (!displayName) return c.json({ error: \"display_name required\" }, 400);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst actor = d.select().from(schema.actors).where(eq(schema.actors.actor_id, actorId)).get();\n\t\tif (!actor) return c.json({ error: \"actor not found\" }, 404);\n\t\tconst updatedAt = new Date().toISOString();\n\t\td.update(schema.actors)\n\t\t\t.set({ display_name: displayName, updated_at: updatedAt })\n\t\t\t.where(eq(schema.actors.actor_id, actorId))\n\t\t\t.run();\n\t\treturn c.json({ ...actor, display_name: displayName, updated_at: updatedAt });\n\t});\n\n\tapp.post(\"/api/sync/actors/merge\", async (c) => {\n\t\tconst store = getStore();\n\t\tensureLocalActorRecord(store);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst primaryActorId = String(body.primary_actor_id ?? \"\").trim();\n\t\tconst secondaryActorId = String(body.secondary_actor_id ?? \"\").trim();\n\t\tif (!primaryActorId) return c.json({ error: \"primary_actor_id required\" }, 400);\n\t\tif (!secondaryActorId) return c.json({ error: \"secondary_actor_id required\" }, 400);\n\t\tif (primaryActorId === secondaryActorId) return c.json({ error: \"actor ids must differ\" }, 400);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst primary = d\n\t\t\t.select()\n\t\t\t.from(schema.actors)\n\t\t\t.where(eq(schema.actors.actor_id, primaryActorId))\n\t\t\t.get();\n\t\tconst secondary = d\n\t\t\t.select()\n\t\t\t.from(schema.actors)\n\t\t\t.where(eq(schema.actors.actor_id, secondaryActorId))\n\t\t\t.get();\n\t\tif (!primary || !secondary) return c.json({ error: \"actor not found\" }, 404);\n\t\tif (primary.status !== \"active\") return c.json({ error: \"primary actor not active\" }, 409);\n\t\tif (secondary.status !== \"active\") return c.json({ error: \"secondary actor not active\" }, 409);\n\t\tif (secondary.is_local && secondary.actor_id === store.actorId) {\n\t\t\treturn c.json({ error: \"cannot merge this device's own local actor\" }, 409);\n\t\t}\n\t\tconst now = new Date().toISOString();\n\t\tconst mergedCount = store.db.transaction(() => {\n\t\t\tconst peerUpdate = d\n\t\t\t\t.update(schema.syncPeers)\n\t\t\t\t.set({ actor_id: primaryActorId })\n\t\t\t\t.where(eq(schema.syncPeers.actor_id, secondaryActorId))\n\t\t\t\t.run();\n\t\t\tif (primary.is_local) {\n\t\t\t\td.update(schema.syncPeers)\n\t\t\t\t\t.set({ claimed_local_actor: 1 })\n\t\t\t\t\t.where(eq(schema.syncPeers.actor_id, primaryActorId))\n\t\t\t\t\t.run();\n\t\t\t}\n\t\t\td.update(schema.actors)\n\t\t\t\t.set({ status: \"merged\", merged_into_actor_id: primaryActorId, updated_at: now })\n\t\t\t\t.where(eq(schema.actors.actor_id, secondaryActorId))\n\t\t\t\t.run();\n\t\t\treturn Number(peerUpdate.changes ?? 0);\n\t\t})();\n\t\treturn c.json({ merged_count: mergedCount });\n\t});\n\n\tapp.post(\"/api/sync/actors/deactivate\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst actorId = String(body.actor_id ?? \"\").trim();\n\t\tif (!actorId) return c.json({ error: \"actor_id required\" }, 400);\n\t\tif (actorId === store.actorId) {\n\t\t\treturn c.json({ error: \"cannot deactivate this device's own local actor\" }, 409);\n\t\t}\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst actor = d.select().from(schema.actors).where(eq(schema.actors.actor_id, actorId)).get();\n\t\tif (!actor) return c.json({ error: \"actor not found\" }, 404);\n\t\tif (actor.status !== \"active\") return c.json({ error: \"actor not active\" }, 409);\n\t\tconst now = new Date().toISOString();\n\t\td.update(schema.actors)\n\t\t\t.set({ status: \"deactivated\", updated_at: now })\n\t\t\t.where(eq(schema.actors.actor_id, actorId))\n\t\t\t.run();\n\t\td.update(schema.syncPeers)\n\t\t\t.set({ actor_id: null })\n\t\t\t.where(eq(schema.syncPeers.actor_id, actorId))\n\t\t\t.run();\n\t\treturn c.json({ ok: true });\n\t});\n\n\tapp.post(\"/api/sync/legacy-devices/claim\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst originDeviceId = String(body.origin_device_id ?? \"\").trim();\n\t\tif (!originDeviceId) return c.json({ error: \"origin_device_id required\" }, 400);\n\t\tconst updated = claimLegacyDeviceAsSelf(store, originDeviceId);\n\t\tif (updated <= 0) return c.json({ error: \"legacy device not found\" }, 404);\n\t\treturn c.json({ ok: true, origin_device_id: originDeviceId, updated });\n\t});\n\n\tapp.post(\"/api/sync/peers/accept-discovered\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\tconst fingerprint = String(body.fingerprint ?? \"\").trim();\n\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\tif (!fingerprint) return c.json({ error: \"fingerprint required\" }, 400);\n\t\ttry {\n\t\t\tconst result = await acceptDiscoveredPeer(store, { peerDeviceId, fingerprint });\n\t\t\tif (!result.ok) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{ error: result.error, detail: result.detail },\n\t\t\t\t\t{ status: result.status as 400 | 404 | 409 },\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json({\n\t\t\t\tok: true,\n\t\t\t\tpeer_device_id: result.peer_device_id,\n\t\t\t\tcreated: result.created,\n\t\t\t\tupdated: result.updated,\n\t\t\t\tname: result.name,\n\t\t\t\tneeds_scope_review: true,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: \"coordinator_lookup_failed\",\n\t\t\t\t\tdetail: error instanceof Error ? error.message : String(error),\n\t\t\t\t},\n\t\t\t\t{ status: 502 },\n\t\t\t);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/invites/create\", async (c) => {\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst groupId = String(body.group_id ?? \"\").trim();\n\t\tconst coordinatorUrl = body.coordinator_url == null ? null : String(body.coordinator_url ?? \"\");\n\t\tconst policy = String(body.policy ?? \"auto_admit\").trim();\n\t\tconst ttlHours = parseInviteTtlHours(body.ttl_hours);\n\t\tif (!groupId) return c.json({ error: \"group_id required\" }, 400);\n\t\tif (body.coordinator_url != null && typeof body.coordinator_url !== \"string\") {\n\t\t\treturn c.json({ error: \"coordinator_url must be string\" }, 400);\n\t\t}\n\t\tif (![\"auto_admit\", \"approval_required\"].includes(policy)) {\n\t\t\treturn c.json({ error: \"policy must be auto_admit or approval_required\" }, 400);\n\t\t}\n\t\tif (ttlHours == null) return c.json({ error: \"ttl_hours must be an integer >= 1\" }, 400);\n\t\ttry {\n\t\t\tconst config = readCoordinatorSyncConfig();\n\t\t\tconst result = await coordinatorCreateInviteAction({\n\t\t\t\tgroupId,\n\t\t\t\tcoordinatorUrl,\n\t\t\t\tpolicy,\n\t\t\t\tttlHours,\n\t\t\t\tcreatedBy: null,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error) }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/invites/import\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst inviteValue = String(body.invite ?? \"\").trim();\n\t\tif (!inviteValue) return c.json({ error: \"invite required\" }, 400);\n\t\ttry {\n\t\t\tconst result = await coordinatorImportInviteAction({ inviteValue, dbPath: store.dbPath });\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error) }, 400);\n\t\t}\n\t});\n\n\tapp.get(\"/api/coordinator/admin/status\", async (c) => {\n\t\tconst status = coordinatorAdminStatusPayload();\n\t\treturn c.json(status);\n\t});\n\n\tapp.get(\"/api/coordinator/admin/groups\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst includeArchived = queryBool(c.req.query(\"include_archived\"));\n\t\ttry {\n\t\t\tconst items = await coordinatorListGroupsAction({\n\t\t\t\tincludeArchived,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ items, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message, status }, 502);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\", status }, 400);\n\t\t}\n\t\tconst groupId = String(body.group_id ?? \"\").trim();\n\t\tconst displayName = String(body.display_name ?? \"\").trim() || null;\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst group = await coordinatorCreateGroupAction({\n\t\t\t\tgroupId,\n\t\t\t\tdisplayName,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ ok: true, group, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/rename\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\", status }, 400);\n\t\t}\n\t\tconst displayName = String(body.display_name ?? \"\").trim();\n\t\tif (!displayName) return c.json({ error: \"display_name required\", status }, 400);\n\t\ttry {\n\t\t\tconst group = await coordinatorRenameGroupAction({\n\t\t\t\tgroupId,\n\t\t\t\tdisplayName,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!group) return c.json({ error: \"group_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, group, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/archive\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst group = await coordinatorArchiveGroupAction({\n\t\t\t\tgroupId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!group) return c.json({ error: \"group_not_found_or_already_archived\", status }, 404);\n\t\t\treturn c.json({ ok: true, group, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/unarchive\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst group = await coordinatorUnarchiveGroupAction({\n\t\t\t\tgroupId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!group) return c.json({ error: \"group_not_found_or_not_archived\", status }, 404);\n\t\t\treturn c.json({ ok: true, group, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/invites\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\", status }, 400);\n\t\t}\n\t\tconst groupId = resolveCoordinatorAdminGroup(String(body.group_id ?? \"\").trim(), status);\n\t\tconst coordinatorUrl = body.coordinator_url == null ? null : String(body.coordinator_url ?? \"\");\n\t\tconst policy = String(body.policy ?? \"auto_admit\").trim();\n\t\tconst ttlHours = parseInviteTtlHours(body.ttl_hours);\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (body.coordinator_url != null && typeof body.coordinator_url !== \"string\") {\n\t\t\treturn c.json({ error: \"coordinator_url must be string\", status }, 400);\n\t\t}\n\t\tif (![\"auto_admit\", \"approval_required\"].includes(policy)) {\n\t\t\treturn c.json({ error: \"policy must be auto_admit or approval_required\", status }, 400);\n\t\t}\n\t\tif (ttlHours == null) {\n\t\t\treturn c.json({ error: \"ttl_hours must be an integer >= 1\", status }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst result = await coordinatorCreateInviteAction({\n\t\t\t\tgroupId,\n\t\t\t\tcoordinatorUrl,\n\t\t\t\tpolicy,\n\t\t\t\tttlHours,\n\t\t\t\tcreatedBy: null,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ ...result, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.get(\"/api/coordinator/admin/join-requests\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = resolveCoordinatorAdminGroup(c.req.query(\"group_id\"), status);\n\t\tif (!groupId) return c.json({ error: \"group_id_required\", status }, 400);\n\t\ttry {\n\t\t\tconst items = await coordinatorListJoinRequestsAction({\n\t\t\t\tgroupId,\n\t\t\t\tremoteUrl: status.coordinator_url,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ items, group_id: groupId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message, status }, 502);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/join-requests/:request_id/approve\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst requestId = String(c.req.param(\"request_id\") ?? \"\").trim();\n\t\tif (!requestId) return c.json({ error: \"request_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst result = await coordinatorReviewJoinRequestAction({\n\t\t\t\trequestId,\n\t\t\t\tapprove: true,\n\t\t\t\treviewedBy: null,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!result) return c.json({ error: \"join request not found\", status }, 404);\n\t\t\treturn c.json({ ok: true, request: result, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json(\n\t\t\t\t{ error: message, status },\n\t\t\t\tmessage.includes(\"request_not_found\") || message.includes(\"not found\") ? 404 : 400,\n\t\t\t);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/join-requests/:request_id/deny\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst requestId = String(c.req.param(\"request_id\") ?? \"\").trim();\n\t\tif (!requestId) return c.json({ error: \"request_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst result = await coordinatorReviewJoinRequestAction({\n\t\t\t\trequestId,\n\t\t\t\tapprove: false,\n\t\t\t\treviewedBy: null,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!result) return c.json({ error: \"join request not found\", status }, 404);\n\t\t\treturn c.json({ ok: true, request: result, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json(\n\t\t\t\t{ error: message, status },\n\t\t\t\tmessage.includes(\"request_not_found\") || message.includes(\"not found\") ? 404 : 400,\n\t\t\t);\n\t\t}\n\t});\n\n\tapp.get(\"/api/coordinator/admin/devices\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = resolveCoordinatorAdminGroup(c.req.query(\"group_id\"), status);\n\t\tif (!groupId) return c.json({ error: \"group_id_required\", status }, 400);\n\t\ttry {\n\t\t\tconst items = await coordinatorListDevicesAction({\n\t\t\t\tgroupId,\n\t\t\t\tincludeDisabled: queryBool(c.req.query(\"include_disabled\")),\n\t\t\t\tremoteUrl: status.coordinator_url,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ items, group_id: groupId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message, status }, 502);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/devices/:device_id/rename\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst deviceId = String(c.req.param(\"device_id\") ?? \"\").trim();\n\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\", status }, 400);\n\t\t}\n\t\tconst groupId = resolveCoordinatorAdminGroup(String(body.group_id ?? \"\").trim(), status);\n\t\tconst displayName = String(body.display_name ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (!displayName) return c.json({ error: \"display_name required\", status }, 400);\n\t\ttry {\n\t\t\tconst device = await coordinatorRenameDeviceAction({\n\t\t\t\tgroupId,\n\t\t\t\tdeviceId,\n\t\t\t\tdisplayName,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!device) return c.json({ error: \"device_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, device, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/devices/:device_id/disable\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst deviceId = String(c.req.param(\"device_id\") ?? \"\").trim();\n\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\tconst groupId = resolveCoordinatorAdminGroup(c.req.query(\"group_id\"), status);\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst ok = await coordinatorDisableDeviceAction({\n\t\t\t\tgroupId,\n\t\t\t\tdeviceId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!ok) return c.json({ error: \"device_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, device_id: deviceId, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/devices/:device_id/remove\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst deviceId = String(c.req.param(\"device_id\") ?? \"\").trim();\n\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\tconst groupId = resolveCoordinatorAdminGroup(c.req.query(\"group_id\"), status);\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst ok = await coordinatorRemoveDeviceAction({\n\t\t\t\tgroupId,\n\t\t\t\tdeviceId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!ok) return c.json({ error: \"device_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, device_id: deviceId, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.get(\"/api/sync/bootstrap-grants\", async (c) => {\n\t\tconst groupId = String(c.req.query(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id_required\" }, 400);\n\t\tconst config = readCoordinatorSyncConfig();\n\t\ttry {\n\t\t\tconst items = await coordinatorListBootstrapGrantsAction({\n\t\t\t\tgroupId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ items });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message }, 500);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/bootstrap-grants/revoke\", async (c) => {\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst grantId = String(body.grant_id ?? \"\").trim();\n\t\tif (!grantId) return c.json({ error: \"grant_id_required\" }, 400);\n\t\tconst config = readCoordinatorSyncConfig();\n\t\ttry {\n\t\t\tconst ok = await coordinatorRevokeBootstrapGrantAction({\n\t\t\t\tgrantId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!ok) return c.json({ error: \"grant_not_found\" }, 404);\n\t\t\treturn c.json({ ok: true, grant_id: grantId });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message }, 500);\n\t\t}\n\t});\n\n\t// DELETE /api/sync/peers/:peer_device_id\n\tapp.delete(\"/api/sync/peers/:peer_device_id\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst peerDeviceId = c.req.param(\"peer_device_id\")?.trim();\n\t\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\t\tconst exists = d\n\t\t\t\t.select({ peer_device_id: schema.syncPeers.peer_device_id })\n\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t\t.get();\n\t\t\tif (!exists) return c.json({ error: \"peer not found\" }, 404);\n\t\t\td.delete(schema.replicationCursors)\n\t\t\t\t.where(eq(schema.replicationCursors.peer_device_id, peerDeviceId))\n\t\t\t\t.run();\n\t\t\td.delete(schema.syncPeers).where(eq(schema.syncPeers.peer_device_id, peerDeviceId)).run();\n\t\t\treturn c.json({ ok: true });\n\t\t}\n\t});\n\n\treturn app;\n}\n","/**\n * @codemem/server — HTTP server (viewer, sync, API).\n *\n * Single HTTP server handling viewer routes and sync daemon.\n * Shares one better-sqlite3 connection between viewer and sync.\n * Embedding inference runs in a worker_thread (lazy-started).\n *\n * Entry: `codemem serve`\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ObserverClient } from \"@codemem/core\";\nimport { MemoryStore, type RawEventSweeper, resolveDbPath, VERSION } from \"@codemem/core\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { Hono } from \"hono\";\nimport { originGuard, preflightHandler } from \"./middleware.js\";\nimport {\n\tcreateInMemoryRequestRateLimiter,\n\ttype InMemoryRequestRateLimiter,\n} from \"./request-rate-limit.js\";\nimport { configRoutes } from \"./routes/config.js\";\nimport { memoryRoutes } from \"./routes/memory.js\";\nimport { observerStatusRoutes } from \"./routes/observer-status.js\";\nimport { rawEventsRoutes } from \"./routes/raw-events.js\";\nimport { statsRoutes } from \"./routes/stats.js\";\nimport { syncProtocolRoutes, syncRoutes } from \"./routes/sync.js\";\n\nexport { VERSION };\n\n/** Shared store instance — SQLite WAL mode handles concurrent reads safely. */\nlet sharedStore: MemoryStore | null = null;\n\n/** Get (or create) the shared store instance. Exported so the sweeper can share it. */\nexport function getStore(): MemoryStore {\n\tif (!sharedStore) {\n\t\tsharedStore = new MemoryStore(resolveDbPath());\n\t}\n\treturn sharedStore;\n}\n\n/** Close the shared store (called on shutdown). */\nexport function closeStore(): void {\n\tsharedStore?.close();\n\tsharedStore = null;\n}\n\n/**\n * Create the Hono app with all viewer routes.\n * Exported for testing — pass a custom store factory to inject test DBs.\n */\nexport interface AppOptions {\n\tstoreFactory?: () => MemoryStore;\n\tsweeper?: RawEventSweeper | null;\n\tobserver?: ObserverClient | null;\n\tsyncRequestRateLimit?: {\n\t\tlimiter?: InMemoryRequestRateLimiter;\n\t\treadLimit?: number;\n\t\tmutationLimit?: number;\n\t\tunauthenticatedReadLimit?: number;\n\t\tunauthenticatedMutationLimit?: number;\n\t};\n\tgetSyncRuntimeStatus?: () => {\n\t\tphase:\n\t\t\t| \"starting\"\n\t\t\t| \"running\"\n\t\t\t| \"stopping\"\n\t\t\t| \"error\"\n\t\t\t| \"disabled\"\n\t\t\t| \"rebootstrapping\"\n\t\t\t| \"needs_attention\"\n\t\t\t| null;\n\t\tdetail?: string | null;\n\t} | null;\n}\n\nexport function createApp(opts?: AppOptions) {\n\tconst storeFactory = opts?.storeFactory ?? getStore;\n\tconst sweeper = opts?.sweeper ?? null;\n\tconst observer = opts?.observer ?? null;\n\tconst getSyncRuntimeStatus = opts?.getSyncRuntimeStatus ?? (() => null);\n\tconst app = new Hono();\n\n\t// CORS / origin guard\n\tapp.use(\"*\", preflightHandler());\n\tapp.use(\"*\", originGuard());\n\n\t// API routes\n\tapp.route(\"/\", statsRoutes(storeFactory));\n\tapp.route(\"/\", memoryRoutes(storeFactory));\n\tapp.route(\n\t\t\"/\",\n\t\tobserverStatusRoutes({\n\t\t\tgetStore: storeFactory,\n\t\t\tgetSweeper: () => sweeper,\n\t\t\tgetObserver: () => observer,\n\t\t}),\n\t);\n\tapp.route(\"/\", configRoutes({ getSweeper: () => sweeper }));\n\tapp.route(\"/\", rawEventsRoutes(storeFactory, sweeper));\n\tapp.route(\"/\", syncRoutes(storeFactory, getSyncRuntimeStatus));\n\n\t// Static assets — serve under /assets/*\n\t// Resolves to packages/viewer-server/static/ both in dev and when installed from npm.\n\tconst staticRoot =\n\t\tprocess.env.CODEMEM_VIEWER_STATIC_DIR ?? join(import.meta.dirname ?? \".\", \"../static\");\n\n\tapp.use(\n\t\t\"/assets/*\",\n\t\tserveStatic({\n\t\t\troot: staticRoot,\n\t\t\trewriteRequestPath: (path) => path.replace(/^\\/assets/, \"\"),\n\t\t}),\n\t);\n\n\t// SPA — serve index.html for root and all client-side routes\n\tconst indexPath = join(staticRoot, \"index.html\");\n\tif (!existsSync(indexPath)) {\n\t\tthrow new Error(\n\t\t\t`Viewer assets missing at ${indexPath}. Run \\`pnpm build\\` from the repo root before starting the viewer.`,\n\t\t);\n\t}\n\tconst indexHtml = readFileSync(indexPath, \"utf-8\");\n\tapp.get(\"*\", (c) => {\n\t\tif (c.req.path.startsWith(\"/api/\")) {\n\t\t\treturn c.json({ error: \"not found\" }, 404);\n\t\t}\n\t\treturn c.html(indexHtml);\n\t});\n\n\treturn app;\n}\n\n/**\n * Create the Hono app for peer-to-peer sync protocol routes only.\n *\n * This app is bound to a separate network-accessible listener\n * (default 0.0.0.0:7337) so remote peers can reach the sync\n * endpoints without exposing the viewer UI or local API routes.\n *\n * No CORS/origin guard is applied — sync requests are authenticated\n * via cryptographic signature verification instead.\n */\nexport function createSyncApp(opts?: AppOptions) {\n\tconst storeFactory = opts?.storeFactory ?? getStore;\n\tconst requestRateLimit = opts?.syncRequestRateLimit ?? {};\n\tconst rateLimiter = requestRateLimit.limiter ?? createInMemoryRequestRateLimiter();\n\tconst readLimit = Math.max(1, Math.trunc(requestRateLimit.readLimit ?? 120));\n\tconst mutationLimit = Math.max(1, Math.trunc(requestRateLimit.mutationLimit ?? 30));\n\tconst app = new Hono();\n\tapp.route(\n\t\t\"/\",\n\t\tsyncProtocolRoutes(storeFactory, {\n\t\t\trouteRateLimit: {\n\t\t\t\tlimiter: rateLimiter,\n\t\t\t\treadLimit,\n\t\t\t\tmutationLimit,\n\t\t\t\tunauthenticatedReadLimit: Math.max(\n\t\t\t\t\t1,\n\t\t\t\t\tMath.trunc(requestRateLimit.unauthenticatedReadLimit ?? Math.min(20, readLimit)),\n\t\t\t\t),\n\t\t\t\tunauthenticatedMutationLimit: Math.max(\n\t\t\t\t\t1,\n\t\t\t\t\tMath.trunc(requestRateLimit.unauthenticatedMutationLimit ?? Math.min(10, mutationLimit)),\n\t\t\t\t),\n\t\t\t},\n\t\t}),\n\t);\n\n\t// Catch-all — return generic 404 to avoid fingerprinting the server.\n\tapp.all(\"*\", (c) => c.json({ error: \"not found\" }, 404));\n\n\treturn app;\n}\n\n// No auto-start — the CLI's `serve` command owns server startup.\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/middleware.ts","../src/request-rate-limit.ts","../src/routes/config.ts","../src/helpers.ts","../src/routes/memory.ts","../src/routes/observer-status.ts","../src/routes/raw-events.ts","../src/routes/stats.ts","../src/routes/sync.ts","../src/index.ts"],"sourcesContent":["/**\n * CORS and cross-origin protection middleware.\n *\n * Ports Python's reject_cross_origin() logic from codemem/viewer_http.py.\n * GETs are allowed from any origin (viewer is local-only).\n * Mutations (POST/DELETE/PATCH/PUT) require an Origin header matching a\n * loopback address, or are rejected with 403.\n */\n\nimport type { Context, Next } from \"hono\";\nimport { createMiddleware } from \"hono/factory\";\n\nconst LOOPBACK_HOSTS = new Set([\"127.0.0.1\", \"localhost\", \"::1\"]);\n\n/**\n * Check whether an Origin header value is a valid loopback URL.\n * Mirrors Python's _is_allowed_loopback_origin_url().\n */\nfunction isLoopbackOrigin(origin: string): boolean {\n\tlet url: URL;\n\ttry {\n\t\turl = new URL(origin);\n\t} catch {\n\t\treturn false;\n\t}\n\tif (url.protocol !== \"http:\" && url.protocol !== \"https:\") return false;\n\tif (url.username || url.password) return false;\n\treturn LOOPBACK_HOSTS.has(url.hostname);\n}\n\n/** HTTP methods that mutate state and require origin validation. */\nconst UNSAFE_METHODS = new Set([\"POST\", \"DELETE\", \"PATCH\", \"PUT\"]);\n\n/**\n * Check whether a missing-Origin request looks like a cross-site browser\n * request. Matches Python's `_is_unsafe_missing_origin()`:\n *\n * - Sec-Fetch-Site present and NOT same-origin/same-site/none → unsafe\n * - Referer present and NOT loopback → unsafe\n * - Otherwise → safe (CLI / programmatic caller, no browser context)\n */\nfunction isUnsafeMissingOrigin(c: Context): boolean {\n\tconst secFetchSite = (c.req.header(\"Sec-Fetch-Site\") ?? \"\").trim().toLowerCase();\n\tif (secFetchSite && ![\"same-origin\", \"same-site\", \"none\"].includes(secFetchSite)) {\n\t\treturn true;\n\t}\n\tconst referer = c.req.header(\"Referer\");\n\tif (!referer) return false;\n\treturn !isLoopbackOrigin(referer);\n}\n\n/**\n * Cross-origin protection middleware.\n *\n * Ports Python's `reject_cross_origin(missing_origin_policy=\"reject_if_unsafe\")`:\n *\n * - GET/HEAD/OPTIONS: allowed from any origin (viewer is local-only).\n * - POST/DELETE/PATCH/PUT:\n * - Origin present + loopback → allowed (browser on localhost)\n * - Origin present + non-loopback → rejected 403\n * - No Origin + no suspicious browser signals → allowed (CLI callers)\n * - No Origin + suspicious Sec-Fetch-Site/Referer → rejected 403\n *\n * For same-origin requests (no Origin header) on safe methods, no\n * Access-Control-Allow-Origin is set — the browser doesn't need it.\n * For valid loopback origins, ACAO is echoed back.\n */\nexport function originGuard() {\n\treturn createMiddleware(async (c: Context, next: Next) => {\n\t\tconst origin = c.req.header(\"Origin\");\n\t\tconst method = c.req.method;\n\n\t\tif (UNSAFE_METHODS.has(method)) {\n\t\t\tif (origin) {\n\t\t\t\t// Origin present — must be loopback\n\t\t\t\tif (!isLoopbackOrigin(origin)) {\n\t\t\t\t\treturn c.json({ error: \"forbidden\" }, 403);\n\t\t\t\t}\n\t\t\t\t// Valid loopback origin — echo it for CORS\n\t\t\t\tc.header(\"Access-Control-Allow-Origin\", origin);\n\t\t\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, DELETE, OPTIONS\");\n\t\t\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\t\t} else {\n\t\t\t\t// No Origin — reject only if browser signals indicate cross-site\n\t\t\t\t// (matches Python's reject_if_unsafe policy for API endpoints)\n\t\t\t\tif (isUnsafeMissingOrigin(c)) {\n\t\t\t\t\treturn c.json({ error: \"forbidden\" }, 403);\n\t\t\t\t}\n\t\t\t\t// CLI / programmatic caller — no CORS headers needed\n\t\t\t}\n\t\t} else if (origin && isLoopbackOrigin(origin)) {\n\t\t\t// Safe method with valid origin — echo for preflight\n\t\t\tc.header(\"Access-Control-Allow-Origin\", origin);\n\t\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, DELETE, OPTIONS\");\n\t\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\t}\n\t\t// No origin or non-loopback on safe method: no ACAO header set.\n\t\t// Browser enforces same-origin; we don't set permissive headers.\n\n\t\tawait next();\n\t});\n}\n\n/**\n * Handle OPTIONS preflight requests.\n * Returns 204 with appropriate CORS headers for loopback origins.\n */\nexport function preflightHandler() {\n\treturn createMiddleware(async (c: Context, next: Next) => {\n\t\tif (c.req.method !== \"OPTIONS\") {\n\t\t\tawait next();\n\t\t\treturn;\n\t\t}\n\t\tconst origin = c.req.header(\"Origin\");\n\t\tif (origin && isLoopbackOrigin(origin)) {\n\t\t\tc.header(\"Access-Control-Allow-Origin\", origin);\n\t\t\tc.header(\"Access-Control-Allow-Methods\", \"GET, POST, DELETE, OPTIONS\");\n\t\t\tc.header(\"Access-Control-Allow-Headers\", \"Content-Type\");\n\t\t\tc.header(\"Access-Control-Max-Age\", \"86400\");\n\t\t\treturn c.body(null, 204);\n\t\t}\n\t\treturn c.body(null, 204);\n\t});\n}\n","import { RateLimiter } from \"limiter\";\n\nexport interface InMemoryRequestRateLimiter {\n\tcheck(key: string, limit: number): { allowed: boolean; retryAfterS: number };\n}\n\nexport function createInMemoryRequestRateLimiter(windowMs = 60_000): InMemoryRequestRateLimiter {\n\tconst safeWindowMs = Math.max(1000, Math.trunc(windowMs));\n\tconst buckets = new Map<string, { limiter: RateLimiter; lastUsedAt: number }>();\n\tlet checks = 0;\n\n\tfunction estimatedRetryAfterS(limit: number): number {\n\t\treturn Math.max(1, Math.ceil(safeWindowMs / Math.max(1, limit) / 1000));\n\t}\n\n\tfunction cleanupExpiredBuckets(currentNow: number): void {\n\t\tif (buckets.size < 64 || checks % 64 !== 0) return;\n\t\tconst staleBefore = currentNow - safeWindowMs * 10;\n\t\tfor (const [key, bucket] of buckets) {\n\t\t\tif (bucket.lastUsedAt < staleBefore) buckets.delete(key);\n\t\t}\n\t}\n\n\treturn {\n\t\tcheck(key: string, limit: number) {\n\t\t\tchecks += 1;\n\t\t\tconst currentNow = Date.now();\n\t\t\tcleanupExpiredBuckets(currentNow);\n\t\t\tconst safeLimit = Math.max(1, Math.trunc(limit));\n\t\t\tconst bucketKey = `${safeLimit}:${key}`;\n\t\t\tlet bucket = buckets.get(bucketKey);\n\t\t\tif (!bucket) {\n\t\t\t\tbucket = {\n\t\t\t\t\tlimiter: new RateLimiter({\n\t\t\t\t\t\ttokensPerInterval: safeLimit,\n\t\t\t\t\t\tinterval: safeWindowMs,\n\t\t\t\t\t\tfireImmediately: true,\n\t\t\t\t\t}),\n\t\t\t\t\tlastUsedAt: currentNow,\n\t\t\t\t};\n\t\t\t\tbuckets.set(bucketKey, bucket);\n\t\t\t}\n\t\t\tbucket.lastUsedAt = currentNow;\n\t\t\tif (bucket.limiter.tryRemoveTokens(1)) {\n\t\t\t\treturn { allowed: true, retryAfterS: 0 };\n\t\t\t}\n\t\t\treturn { allowed: false, retryAfterS: estimatedRetryAfterS(safeLimit) };\n\t\t},\n\t};\n}\n","/**\n * Config routes — GET /api/config, POST /api/config.\n *\n * Ports the user-facing config read/write path from Python's\n * codemem/viewer_routes/config.py, scoped to the TS runtime's current needs.\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { join } from \"node:path\";\nimport {\n\tCODEMEM_CONFIG_ENV_OVERRIDES,\n\tgetCodememConfigPath,\n\tgetCodememEnvOverrides,\n\tlistObserverProviderOptions,\n\ttype RawEventSweeper,\n\treadCodememConfigFile,\n\tstripJsonComments,\n\tstripTrailingCommas,\n\twriteCodememConfigFile,\n} from \"@codemem/core\";\nimport { Hono } from \"hono\";\n\ntype ConfigData = Record<string, unknown>;\n\nconst REDACTED_VALUE = \"[redacted]\";\n\nconst RUNTIMES = new Set([\"api_http\", \"claude_sidecar\"]);\nconst AUTH_SOURCES = new Set([\"auto\", \"env\", \"file\", \"command\", \"none\"]);\nconst HOT_RELOAD_KEYS = new Set([\"raw_events_sweeper_interval_s\"]);\nconst PROTECTED_WRITE_KEYS = new Set<string>([\n\t\"claude_command\",\n\t\"observer_base_url\",\n\t\"observer_auth_file\",\n\t\"observer_auth_command\",\n\t\"observer_headers\",\n\t\"sync_coordinator_url\",\n] as const);\nconst SECRET_CONFIG_KEYS = new Set<string>([\n\t\"observer_auth_file\",\n\t\"observer_auth_command\",\n\t\"observer_headers\",\n\t\"sync_coordinator_admin_secret\",\n] as const);\nconst ALLOWED_KEYS = [\n\t\"claude_command\",\n\t\"observer_base_url\",\n\t\"observer_provider\",\n\t\"observer_model\",\n\t\"observer_tier_routing_enabled\",\n\t\"observer_simple_model\",\n\t\"observer_simple_temperature\",\n\t\"observer_rich_model\",\n\t\"observer_rich_temperature\",\n\t\"observer_rich_openai_use_responses\",\n\t\"observer_rich_reasoning_effort\",\n\t\"observer_rich_reasoning_summary\",\n\t\"observer_rich_max_output_tokens\",\n\t\"observer_runtime\",\n\t\"observer_auth_source\",\n\t\"observer_auth_file\",\n\t\"observer_auth_command\",\n\t\"observer_auth_timeout_ms\",\n\t\"observer_auth_cache_ttl_s\",\n\t\"observer_headers\",\n\t\"observer_max_chars\",\n\t\"pack_observation_limit\",\n\t\"pack_session_limit\",\n\t\"sync_enabled\",\n\t\"sync_retention_enabled\",\n\t\"sync_retention_max_age_days\",\n\t\"sync_retention_max_size_mb\",\n\t\"sync_host\",\n\t\"sync_port\",\n\t\"sync_interval_s\",\n\t\"sync_mdns\",\n\t\"sync_coordinator_url\",\n\t\"sync_coordinator_group\",\n\t\"sync_coordinator_timeout_s\",\n\t\"sync_coordinator_presence_ttl_s\",\n\t\"raw_events_sweeper_interval_s\",\n] as const;\n\nconst DEFAULTS: ConfigData = {\n\tclaude_command: [\"claude\"],\n\tobserver_runtime: \"api_http\",\n\tobserver_auth_source: \"auto\",\n\tobserver_tier_routing_enabled: false,\n\tobserver_rich_openai_use_responses: false,\n\tobserver_auth_command: [],\n\tobserver_auth_timeout_ms: 1500,\n\tobserver_auth_cache_ttl_s: 300,\n\tobserver_headers: {},\n\tobserver_max_chars: 12000,\n\tpack_observation_limit: 50,\n\tpack_session_limit: 10,\n\tsync_enabled: false,\n\tsync_retention_enabled: false,\n\tsync_retention_max_age_days: 30,\n\tsync_retention_max_size_mb: 512,\n\tsync_host: \"0.0.0.0\",\n\tsync_port: 7337,\n\tsync_interval_s: 120,\n\tsync_mdns: true,\n\tsync_coordinator_timeout_s: 3,\n\tsync_coordinator_presence_ttl_s: 180,\n\traw_events_sweeper_interval_s: 30,\n};\n\nexport interface ConfigRouteOptions {\n\tgetSweeper?: () => RawEventSweeper | null;\n}\n\nfunction loadProviderOptions(): string[] {\n\treturn listObserverProviderOptions();\n}\n\nfunction getConfigPath(): string {\n\tconst envPath = process.env.CODEMEM_CONFIG;\n\tif (envPath) return envPath.replace(/^~/, homedir());\n\tconst configDir = join(homedir(), \".config\", \"codemem\");\n\tconst candidates = [join(configDir, \"config.json\"), join(configDir, \"config.jsonc\")];\n\treturn candidates.find((p) => existsSync(p)) ?? join(configDir, \"config.json\");\n}\n\nfunction readConfigFile(configPath: string): ConfigData {\n\tif (!existsSync(configPath)) return {};\n\ttry {\n\t\tlet text = readFileSync(configPath, \"utf-8\").trim();\n\t\tif (!text) return {};\n\t\ttry {\n\t\t\treturn JSON.parse(text) as ConfigData;\n\t\t} catch {\n\t\t\ttext = stripTrailingCommas(stripJsonComments(text));\n\t\t\treturn JSON.parse(text) as ConfigData;\n\t\t}\n\t} catch {\n\t\treturn {};\n\t}\n}\n\nfunction getEffectiveConfig(configData: ConfigData): ConfigData {\n\tconst effective: ConfigData = { ...DEFAULTS, ...configData };\n\tfor (const [key, envVar] of Object.entries(CODEMEM_CONFIG_ENV_OVERRIDES) as Array<\n\t\t[string, string]\n\t>) {\n\t\tconst val = process.env[envVar];\n\t\tif (val != null && val !== \"\") effective[key] = val;\n\t}\n\treturn effective;\n}\n\nfunction redactConfigValue(key: string, value: unknown): unknown {\n\tif (value == null || !SECRET_CONFIG_KEYS.has(key)) return value;\n\tif (Array.isArray(value)) return value.length > 0 ? REDACTED_VALUE : [];\n\tif (typeof value === \"object\") {\n\t\treturn Object.keys(value as Record<string, unknown>).length > 0 ? REDACTED_VALUE : {};\n\t}\n\tif (typeof value === \"string\") return value.trim() ? REDACTED_VALUE : \"\";\n\treturn REDACTED_VALUE;\n}\n\nfunction sanitizeConfigForResponse(configData: ConfigData): ConfigData {\n\tconst sanitized: ConfigData = {};\n\tfor (const [key, value] of Object.entries(configData)) {\n\t\tsanitized[key] = redactConfigValue(key, value);\n\t}\n\treturn sanitized;\n}\n\nfunction configValuesEqual(left: unknown, right: unknown): boolean {\n\tif (Object.is(left, right)) return true;\n\tif (left == null || right == null) return left == null && right == null;\n\tif (typeof left === \"object\" || typeof right === \"object\") {\n\t\treturn JSON.stringify(left) === JSON.stringify(right);\n\t}\n\treturn false;\n}\n\nfunction partitionViewerUpdates(\n\tupdates: ConfigData,\n\tbeforeConfig: ConfigData,\n): { allowedUpdates: ConfigData; error: string | null } {\n\tconst allowedUpdates: ConfigData = {};\n\tfor (const [key, value] of Object.entries(updates)) {\n\t\tif (!PROTECTED_WRITE_KEYS.has(key)) {\n\t\t\tallowedUpdates[key] = value;\n\t\t\tcontinue;\n\t\t}\n\t\tif (SECRET_CONFIG_KEYS.has(key) && value === REDACTED_VALUE) {\n\t\t\tcontinue;\n\t\t}\n\t\tif (configValuesEqual(value, beforeConfig[key])) {\n\t\t\tcontinue;\n\t\t}\n\t\treturn {\n\t\t\tallowedUpdates: {},\n\t\t\terror: `${key} cannot be changed from the viewer API; edit the config file or environment instead`,\n\t\t};\n\t}\n\treturn { allowedUpdates, error: null };\n}\n\nfunction parsePositiveInt(value: unknown, allowZero = false): number | null {\n\tif (typeof value === \"boolean\") return null;\n\tconst parsed =\n\t\ttypeof value === \"number\"\n\t\t\t? value\n\t\t\t: typeof value === \"string\" && /^-?\\d+$/.test(value.trim())\n\t\t\t\t? Number(value.trim())\n\t\t\t\t: Number.NaN;\n\tif (!Number.isFinite(parsed) || !Number.isInteger(parsed)) return null;\n\tif (allowZero) return parsed >= 0 ? parsed : null;\n\treturn parsed > 0 ? parsed : null;\n}\n\nfunction parseFiniteNumber(value: unknown, allowZero = true): number | null {\n\tif (typeof value === \"boolean\") return null;\n\tconst parsed =\n\t\ttypeof value === \"number\"\n\t\t\t? value\n\t\t\t: typeof value === \"string\" && value.trim().length > 0\n\t\t\t\t? Number(value.trim())\n\t\t\t\t: Number.NaN;\n\tif (!Number.isFinite(parsed)) return null;\n\tif (allowZero) return parsed >= 0 ? parsed : null;\n\treturn parsed > 0 ? parsed : null;\n}\n\nfunction asStringMap(value: unknown): Record<string, string> | null {\n\tif (value == null || typeof value !== \"object\" || Array.isArray(value)) return null;\n\tconst parsed: Record<string, string> = {};\n\tfor (const [key, item] of Object.entries(value)) {\n\t\tif (typeof item !== \"string\") return null;\n\t\tconst stripped = key.trim();\n\t\tif (!stripped) return null;\n\t\tparsed[stripped] = item;\n\t}\n\treturn parsed;\n}\n\nfunction asExecutableArgv(value: unknown): string[] | null {\n\tif (!Array.isArray(value)) return null;\n\tconst argv: string[] = [];\n\tfor (const item of value) {\n\t\tif (typeof item !== \"string\") return null;\n\t\tconst token = item.trim();\n\t\tif (!token) return null;\n\t\targv.push(token);\n\t}\n\treturn argv;\n}\n\nfunction validateAndApplyUpdate(\n\tconfigData: ConfigData,\n\tkey: (typeof ALLOWED_KEYS)[number],\n\tvalue: unknown,\n\tproviders: Set<string>,\n): string | null {\n\tif (value == null || value === \"\") {\n\t\tdelete configData[key];\n\t\treturn null;\n\t}\n\tif (key === \"observer_provider\") {\n\t\tif (typeof value !== \"string\") return \"observer_provider must be string\";\n\t\tconst provider = value.trim().toLowerCase();\n\t\tconst savedBaseUrl = configData.observer_base_url;\n\t\tconst hasSavedBaseUrl = typeof savedBaseUrl === \"string\" && savedBaseUrl.trim().length > 0;\n\t\tif (!providers.has(provider) && !hasSavedBaseUrl) {\n\t\t\treturn \"observer_provider must match a configured provider\";\n\t\t}\n\t\tconfigData[key] = provider;\n\t\treturn null;\n\t}\n\tif (key === \"observer_runtime\") {\n\t\tif (typeof value !== \"string\") return \"observer_runtime must be string\";\n\t\tconst runtime = value.trim().toLowerCase();\n\t\tif (!RUNTIMES.has(runtime)) {\n\t\t\treturn \"observer_runtime must be one of: api_http, claude_sidecar\";\n\t\t}\n\t\tconfigData[key] = runtime;\n\t\treturn null;\n\t}\n\tif (key === \"observer_auth_source\") {\n\t\tif (typeof value !== \"string\") return \"observer_auth_source must be string\";\n\t\tconst source = value.trim().toLowerCase();\n\t\tif (!AUTH_SOURCES.has(source)) {\n\t\t\treturn \"observer_auth_source must be one of: auto, env, file, command, none\";\n\t\t}\n\t\tconfigData[key] = source;\n\t\treturn null;\n\t}\n\tif (key === \"claude_command\" || key === \"observer_auth_command\") {\n\t\tconst argv = asExecutableArgv(value);\n\t\tif (argv == null) return `${key} must be string array`;\n\t\tif (argv.length > 0) configData[key] = argv;\n\t\telse delete configData[key];\n\t\treturn null;\n\t}\n\tif (key === \"observer_headers\") {\n\t\tconst headers = asStringMap(value);\n\t\tif (headers == null) return \"observer_headers must be object of string values\";\n\t\tif (Object.keys(headers).length > 0) configData[key] = headers;\n\t\telse delete configData[key];\n\t\treturn null;\n\t}\n\tif (key === \"sync_enabled\" || key === \"sync_retention_enabled\" || key === \"sync_mdns\") {\n\t\tif (typeof value !== \"boolean\") return `${key} must be boolean`;\n\t\tconfigData[key] = value;\n\t\treturn null;\n\t}\n\tif (key === \"observer_tier_routing_enabled\" || key === \"observer_rich_openai_use_responses\") {\n\t\tif (typeof value !== \"boolean\") return `${key} must be boolean`;\n\t\tconfigData[key] = value;\n\t\treturn null;\n\t}\n\tif (\n\t\tkey === \"observer_base_url\" ||\n\t\tkey === \"observer_model\" ||\n\t\tkey === \"observer_simple_model\" ||\n\t\tkey === \"observer_rich_model\" ||\n\t\tkey === \"observer_rich_reasoning_effort\" ||\n\t\tkey === \"observer_rich_reasoning_summary\" ||\n\t\tkey === \"observer_auth_file\" ||\n\t\tkey === \"sync_host\" ||\n\t\tkey === \"sync_coordinator_url\" ||\n\t\tkey === \"sync_coordinator_group\"\n\t) {\n\t\tif (typeof value !== \"string\") return `${key} must be string`;\n\t\tconst trimmed = value.trim();\n\t\tif (!trimmed) delete configData[key];\n\t\telse configData[key] = trimmed;\n\t\treturn null;\n\t}\n\tif (key === \"observer_simple_temperature\" || key === \"observer_rich_temperature\") {\n\t\tconst parsed = parseFiniteNumber(value, true);\n\t\tif (parsed == null) return `${key} must be non-negative number`;\n\t\tconfigData[key] = parsed;\n\t\treturn null;\n\t}\n\tconst allowZero = key === \"observer_auth_cache_ttl_s\";\n\tconst parsed = parsePositiveInt(value, allowZero);\n\tif (parsed == null) return `${key} must be ${allowZero ? \"non-negative int\" : \"int\"}`;\n\tconfigData[key] = parsed;\n\treturn null;\n}\n\nfunction applyRuntimeEffects(changedKeys: string[], opts: ConfigRouteOptions): string[] {\n\tconst applied: string[] = [];\n\tif (changedKeys.includes(\"raw_events_sweeper_interval_s\")) {\n\t\tconst configValue = readCodememConfigFile().raw_events_sweeper_interval_s;\n\t\tconst seconds =\n\t\t\ttypeof configValue === \"number\"\n\t\t\t\t? configValue\n\t\t\t\t: Number.parseInt(String(configValue ?? \"\"), 10);\n\t\tif (Number.isFinite(seconds) && seconds > 0) {\n\t\t\tprocess.env.CODEMEM_RAW_EVENTS_SWEEPER_INTERVAL_MS = String(seconds * 1000);\n\t\t} else {\n\t\t\tdelete process.env.CODEMEM_RAW_EVENTS_SWEEPER_INTERVAL_MS;\n\t\t}\n\t\topts.getSweeper?.()?.notifyConfigChanged();\n\t\tapplied.push(\"raw_events_sweeper_interval_s\");\n\t}\n\treturn applied;\n}\n\nexport function configRoutes(opts: ConfigRouteOptions = {}) {\n\tconst app = new Hono();\n\n\tapp.get(\"/api/config\", (c) => {\n\t\tconst configPath = getConfigPath();\n\t\tconst configData = readConfigFile(configPath);\n\t\tconst effective = getEffectiveConfig(configData);\n\t\treturn c.json({\n\t\t\tpath: configPath,\n\t\t\tconfig: sanitizeConfigForResponse(configData),\n\t\t\tdefaults: DEFAULTS,\n\t\t\teffective: sanitizeConfigForResponse(effective),\n\t\t\tenv_overrides: getCodememEnvOverrides(),\n\t\t\tprotected_keys: [...PROTECTED_WRITE_KEYS].sort(),\n\t\t\tproviders: loadProviderOptions(),\n\t\t});\n\t});\n\n\tapp.post(\"/api/config\", async (c) => {\n\t\tlet payload: unknown;\n\t\ttry {\n\t\t\tpayload = (await c.req.json()) as unknown;\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tif (payload == null || typeof payload !== \"object\" || Array.isArray(payload)) {\n\t\t\treturn c.json({ error: \"payload must be an object\" }, 400);\n\t\t}\n\t\tif (\n\t\t\t\"config\" in payload &&\n\t\t\t(payload as ConfigData).config != null &&\n\t\t\t(typeof (payload as ConfigData).config !== \"object\" ||\n\t\t\t\tArray.isArray((payload as ConfigData).config))\n\t\t) {\n\t\t\treturn c.json({ error: \"config must be an object\" }, 400);\n\t\t}\n\t\tconst updates =\n\t\t\t\"config\" in payload &&\n\t\t\t(payload as ConfigData).config != null &&\n\t\t\ttypeof (payload as ConfigData).config === \"object\" &&\n\t\t\t!Array.isArray((payload as ConfigData).config)\n\t\t\t\t? ((payload as ConfigData).config as ConfigData)\n\t\t\t\t: (payload as ConfigData);\n\n\t\tconst configPath = getCodememConfigPath();\n\t\tconst beforeConfig = readCodememConfigFile();\n\t\tconst { allowedUpdates, error: protectedKeyError } = partitionViewerUpdates(\n\t\t\tupdates,\n\t\t\tbeforeConfig,\n\t\t);\n\t\tif (protectedKeyError) {\n\t\t\treturn c.json({ error: protectedKeyError }, 403);\n\t\t}\n\n\t\tconst beforeEffective = getEffectiveConfig(beforeConfig);\n\t\tconst nextConfig: ConfigData = { ...beforeConfig };\n\t\tconst providers = new Set(loadProviderOptions());\n\n\t\tconst touchedKeys = ALLOWED_KEYS.filter((key) => key in allowedUpdates);\n\t\tfor (const key of ALLOWED_KEYS) {\n\t\t\tif (!(key in allowedUpdates)) continue;\n\t\t\tconst error = validateAndApplyUpdate(nextConfig, key, allowedUpdates[key], providers);\n\t\t\tif (error) return c.json({ error }, 400);\n\t\t}\n\n\t\tlet savedPath: string;\n\t\ttry {\n\t\t\tsavedPath = writeCodememConfigFile(nextConfig, configPath);\n\t\t} catch {\n\t\t\treturn c.json({ error: \"failed to write config\" }, 500);\n\t\t}\n\n\t\tconst afterEffective = getEffectiveConfig(nextConfig);\n\t\tconst savedChangedKeys = ALLOWED_KEYS.filter((key) => beforeConfig[key] !== nextConfig[key]);\n\t\tconst effectiveChangedKeys = ALLOWED_KEYS.filter(\n\t\t\t(key) => beforeEffective[key] !== afterEffective[key],\n\t\t);\n\t\tconst envOverrides = getCodememEnvOverrides();\n\t\tconst ignoredByEnvKeys = savedChangedKeys.filter(\n\t\t\t(key) => !effectiveChangedKeys.includes(key) && key in envOverrides,\n\t\t);\n\t\tconst runtimeChangedKeys = [\n\t\t\t...new Set([...touchedKeys, ...savedChangedKeys, ...effectiveChangedKeys]),\n\t\t];\n\t\tconst hotReloadedKeys = applyRuntimeEffects(runtimeChangedKeys, opts);\n\t\tconst restartRequiredKeys = effectiveChangedKeys.filter(\n\t\t\t(key) => !HOT_RELOAD_KEYS.has(key) && !(key in envOverrides),\n\t\t);\n\n\t\treturn c.json({\n\t\t\tpath: savedPath,\n\t\t\tconfig: sanitizeConfigForResponse(nextConfig),\n\t\t\teffective: sanitizeConfigForResponse(afterEffective),\n\t\t\tprotected_keys: [...PROTECTED_WRITE_KEYS].sort(),\n\t\t\teffects: {\n\t\t\t\tsaved_keys: savedChangedKeys,\n\t\t\t\teffective_keys: effectiveChangedKeys,\n\t\t\t\thot_reloaded_keys: hotReloadedKeys,\n\t\t\t\trestart_required_keys: restartRequiredKeys,\n\t\t\t\tignored_by_env_keys: ignoredByEnvKeys,\n\t\t\t\twarnings: ignoredByEnvKeys.map(\n\t\t\t\t\t(key) =>\n\t\t\t\t\t\t`${key} is currently controlled by ${envOverrides[key]}; saved config will not take effect until that override is removed.`,\n\t\t\t\t),\n\t\t\t},\n\t\t});\n\t});\n\n\treturn app;\n}\n","import { parseStrictInteger } from \"@codemem/core\";\n\n/**\n * Shared helpers for viewer-server routes.\n */\n\n/**\n * Parse a JSON string that should be an array of strings.\n * Returns an empty array on null, invalid JSON, or non-array values.\n * Mirrors Python's store._safe_json_list().\n */\nexport function safeJsonList(raw: string | null | undefined): string[] {\n\tif (raw == null) return [];\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(raw);\n\t\tif (!Array.isArray(parsed)) return [];\n\t\treturn parsed.filter((item): item is string => typeof item === \"string\");\n\t} catch {\n\t\treturn [];\n\t}\n}\n\n/**\n * Parse a query parameter as an integer, returning the default on failure.\n */\nexport function queryInt(value: string | undefined, defaultValue: number): number {\n\tif (value == null) return defaultValue;\n\tconst parsed = parseStrictInteger(value);\n\treturn parsed == null ? defaultValue : parsed;\n}\n\n/**\n * Parse a query parameter as a boolean flag.\n * Recognizes \"1\", \"true\", \"yes\" as truthy.\n */\nexport function queryBool(value: string | undefined): boolean {\n\tif (value == null) return false;\n\treturn value === \"1\" || value === \"true\" || value === \"yes\";\n}\n","/**\n * Memory routes — observations, summaries, sessions, projects, pack, artifacts.\n */\n\nimport type { MemoryStore } from \"@codemem/core\";\nimport {\n\tbuildFilterClausesWithContext,\n\tcanonicalMemoryKind,\n\tfromJson,\n\tisSummaryLikeMemory as isCoreSummaryLikeMemory,\n\tparseStrictInteger,\n\tschema,\n} from \"@codemem/core\";\nimport { desc, eq, inArray, isNotNull } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { Hono } from \"hono\";\nimport { queryInt } from \"../helpers.js\";\n\ntype StoreFactory = () => MemoryStore;\n\ntype OwnershipContext = {\n\tactorId: string;\n\tclaimedPeerIds: Set<string>;\n\tdeviceId: string;\n\tlegacyActorIds: Set<string>;\n};\n\nfunction cleanOwnershipValue(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst trimmed = value.trim();\n\treturn trimmed ? trimmed : null;\n}\n\nfunction buildOwnershipContext(store: MemoryStore): OwnershipContext {\n\tconst claimedPeerIds = new Set(store.sameActorPeerIds());\n\treturn {\n\t\tactorId: store.actorId,\n\t\tclaimedPeerIds,\n\t\tdeviceId: store.deviceId,\n\t\tlegacyActorIds: new Set(Array.from(claimedPeerIds, (peerId) => `legacy-sync:${peerId}`)),\n\t};\n}\n\nfunction memoryOwnedBySelf(\n\trow: Record<string, unknown>,\n\townership: OwnershipContext,\n\tmetadata = fromJson((row.metadata_json as string) ?? null),\n): boolean {\n\tconst meta = metadata as Record<string, unknown>;\n\tconst actorId = cleanOwnershipValue(row.actor_id) ?? cleanOwnershipValue(meta.actor_id);\n\tif (actorId === ownership.actorId) return true;\n\n\tconst deviceId =\n\t\tcleanOwnershipValue(row.origin_device_id) ?? cleanOwnershipValue(meta.origin_device_id);\n\tif (deviceId === ownership.deviceId) return true;\n\tif (deviceId && ownership.claimedPeerIds.has(deviceId)) return true;\n\tif (actorId && ownership.legacyActorIds.has(actorId)) return true;\n\n\treturn false;\n}\n\nfunction serializeMemoryRow(\n\townership: OwnershipContext,\n\trow: Record<string, unknown>,\n): Record<string, unknown> {\n\tconst metadata = fromJson((row.metadata_json as string) ?? null);\n\tconst item = {\n\t\t...row,\n\t\tkind: canonicalMemoryKind((row.kind as string | null | undefined) ?? null, row.metadata_json),\n\t\tmetadata_json: metadata,\n\t};\n\treturn {\n\t\t...item,\n\t\towned_by_self: memoryOwnedBySelf(row, ownership, metadata),\n\t};\n}\n\n/**\n * Attach session project/cwd fields to memory items.\n */\nfunction attachSessionFields(store: MemoryStore, items: Record<string, unknown>[]): void {\n\tconst sessionIds: number[] = [];\n\tconst seen = new Set<number>();\n\tfor (const item of items) {\n\t\tconst value = item.session_id;\n\t\tif (value == null) continue;\n\t\tconst sid = Number(value);\n\t\tif (Number.isNaN(sid) || seen.has(sid)) continue;\n\t\tseen.add(sid);\n\t\tsessionIds.push(sid);\n\t}\n\tif (sessionIds.length === 0) return;\n\n\tconst d = drizzle(store.db, { schema });\n\tconst rows = d\n\t\t.select({\n\t\t\tid: schema.sessions.id,\n\t\t\tproject: schema.sessions.project,\n\t\t\tcwd: schema.sessions.cwd,\n\t\t})\n\t\t.from(schema.sessions)\n\t\t.where(inArray(schema.sessions.id, sessionIds))\n\t\t.all();\n\n\tconst bySession = new Map<number, { project: string; cwd: string }>();\n\tfor (const row of rows) {\n\t\tconst projectRaw = String(row.project ?? \"\").trim();\n\t\tconst project = projectRaw ? projectBasename(projectRaw) : \"\";\n\t\tconst cwd = String(row.cwd ?? \"\");\n\t\tbySession.set(row.id, { project, cwd });\n\t}\n\n\tfor (const item of items) {\n\t\tconst sid = Number(item.session_id);\n\t\tif (Number.isNaN(sid)) continue;\n\t\tconst fields = bySession.get(sid);\n\t\tif (!fields) continue;\n\t\titem.project ??= fields.project;\n\t\titem.cwd ??= fields.cwd;\n\t}\n}\n\n/**\n * Extract the basename of a project path.\n * Strips \"fatal:\" prefixed values.\n */\nfunction projectBasename(raw: string): string {\n\tif (raw.toLowerCase().startsWith(\"fatal:\")) return \"\";\n\tconst parts = raw.replace(/\\\\/g, \"/\").split(\"/\");\n\treturn parts[parts.length - 1] ?? raw;\n}\n\nfunction normalizeScope(raw: string | undefined): \"mine\" | \"theirs\" | undefined {\n\tconst value = String(raw ?? \"\")\n\t\t.trim()\n\t\t.toLowerCase();\n\tif (value === \"mine\" || value === \"theirs\") return value;\n\treturn undefined;\n}\n\nfunction queryMemoryPage(\n\tstore: MemoryStore,\n\toptions: {\n\t\tlimit: number;\n\t\toffset: number;\n\t\tproject?: string;\n\t\tscope?: \"mine\" | \"theirs\";\n\t},\n): Record<string, unknown>[] {\n\tconst filters: Record<string, unknown> = {};\n\tif (options.project) filters.project = options.project;\n\tif (options.scope) filters.ownership_scope = options.scope;\n\n\tconst filterResult = buildFilterClausesWithContext(filters, {\n\t\tactorId: store.actorId,\n\t\tdeviceId: store.deviceId,\n\t});\n\tconst clauses = [\"memory_items.active = 1\", ...filterResult.clauses];\n\tconst where = clauses.join(\" AND \");\n\tconst from = filterResult.joinSessions\n\t\t? \"memory_items JOIN sessions ON sessions.id = memory_items.session_id\"\n\t\t: \"memory_items\";\n\n\tconst rows = store.db\n\t\t.prepare(\n\t\t\t`SELECT memory_items.* FROM ${from}\n\t\t\t WHERE ${where}\n\t\t\t ORDER BY memory_items.created_at DESC\n\t\t\t LIMIT ? OFFSET ?`,\n\t\t)\n\t\t.all(...filterResult.params, options.limit + 1, options.offset) as Record<string, unknown>[];\n\n\tconst ownership = buildOwnershipContext(store);\n\treturn rows.map((row) => serializeMemoryRow(ownership, row));\n}\n\nfunction isSummaryLikeMemory(item: Record<string, unknown>): boolean {\n\treturn isCoreSummaryLikeMemory({\n\t\tkind: item.kind as string | null | undefined,\n\t\tmetadata: item.metadata_json,\n\t});\n}\n\nfunction selectMemoryPage(\n\tstore: MemoryStore,\n\toptions: {\n\t\tlimit: number;\n\t\toffset: number;\n\t\tproject?: string;\n\t\tscope?: \"mine\" | \"theirs\";\n\t\tmatcher: (item: Record<string, unknown>) => boolean;\n\t},\n): Record<string, unknown>[] {\n\tconst pageSize = Math.max(options.limit + options.offset + 10, 50);\n\tlet rawOffset = 0;\n\tconst matched: Record<string, unknown>[] = [];\n\n\twhile (matched.length < options.offset + options.limit + 1) {\n\t\tconst page = queryMemoryPage(store, {\n\t\t\tlimit: pageSize,\n\t\t\toffset: rawOffset,\n\t\t\tproject: options.project,\n\t\t\tscope: options.scope,\n\t\t});\n\t\tif (page.length === 0) break;\n\t\tmatched.push(...page.filter(options.matcher));\n\t\tif (page.length < pageSize) break;\n\t\trawOffset += page.length;\n\t}\n\n\treturn matched.slice(options.offset, options.offset + options.limit + 1);\n}\n\nexport function memoryRoutes(getStore: StoreFactory) {\n\tconst app = new Hono();\n\n\t// GET /api/sessions\n\tapp.get(\"/api/sessions\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst limit = queryInt(c.req.query(\"limit\"), 20);\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst rows = d\n\t\t\t\t.select()\n\t\t\t\t.from(schema.sessions)\n\t\t\t\t.orderBy(desc(schema.sessions.started_at))\n\t\t\t\t.limit(limit)\n\t\t\t\t.all();\n\t\t\tconst items = rows.map((row) => ({\n\t\t\t\t...row,\n\t\t\t\tmetadata_json: fromJson(row.metadata_json),\n\t\t\t}));\n\t\t\treturn c.json({ items });\n\t\t}\n\t});\n\n\t// GET /api/projects\n\tapp.get(\"/api/projects\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst rows = d\n\t\t\t\t.selectDistinct({ project: schema.sessions.project })\n\t\t\t\t.from(schema.sessions)\n\t\t\t\t.where(isNotNull(schema.sessions.project))\n\t\t\t\t.all();\n\t\t\tconst projects = [\n\t\t\t\t...new Set(\n\t\t\t\t\trows\n\t\t\t\t\t\t.map((r) => String(r.project ?? \"\").trim())\n\t\t\t\t\t\t.filter((p) => p && !p.toLowerCase().startsWith(\"fatal:\"))\n\t\t\t\t\t\t.map((p) => projectBasename(p))\n\t\t\t\t\t\t.filter(Boolean),\n\t\t\t\t),\n\t\t\t].sort();\n\t\t\treturn c.json({ projects });\n\t\t}\n\t});\n\n\t// GET /api/observations (aliased from /api/memories)\n\tapp.get(\"/api/memories\", (c) => {\n\t\tconst search = new URL(c.req.url).search;\n\t\treturn c.redirect(`/api/observations${search}`, 301);\n\t});\n\n\tapp.get(\"/api/observations\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst limit = Math.max(1, queryInt(c.req.query(\"limit\"), 20));\n\t\t\tconst offset = Math.max(0, queryInt(c.req.query(\"offset\"), 0));\n\t\t\tconst project = c.req.query(\"project\") || undefined;\n\t\t\tconst scope = normalizeScope(c.req.query(\"scope\"));\n\t\t\tconst items = selectMemoryPage(store, {\n\t\t\t\tlimit,\n\t\t\t\toffset,\n\t\t\t\tproject,\n\t\t\t\tscope,\n\t\t\t\tmatcher: (item) => !isSummaryLikeMemory(item),\n\t\t\t});\n\t\t\tconst hasMore = items.length > limit;\n\t\t\tconst result = hasMore ? items.slice(0, limit) : items;\n\t\t\tconst asRecords = result as unknown as Record<string, unknown>[];\n\t\t\tattachSessionFields(store, asRecords);\n\t\t\treturn c.json({\n\t\t\t\titems: asRecords,\n\t\t\t\tpagination: {\n\t\t\t\t\tlimit,\n\t\t\t\t\toffset,\n\t\t\t\t\tnext_offset: hasMore ? offset + result.length : null,\n\t\t\t\t\thas_more: hasMore,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t});\n\n\t// GET /api/summaries\n\tapp.get(\"/api/summaries\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst limit = Math.max(1, queryInt(c.req.query(\"limit\"), 50));\n\t\t\tconst offset = Math.max(0, queryInt(c.req.query(\"offset\"), 0));\n\t\t\tconst project = c.req.query(\"project\") || undefined;\n\t\t\tconst scope = normalizeScope(c.req.query(\"scope\"));\n\t\t\tconst items = selectMemoryPage(store, {\n\t\t\t\tlimit,\n\t\t\t\toffset,\n\t\t\t\tproject,\n\t\t\t\tscope,\n\t\t\t\tmatcher: (item) => isSummaryLikeMemory(item),\n\t\t\t});\n\t\t\tconst hasMore = items.length > limit;\n\t\t\tconst result = hasMore ? items.slice(0, limit) : items;\n\t\t\tconst asRecords = result as unknown as Record<string, unknown>[];\n\t\t\tattachSessionFields(store, asRecords);\n\t\t\treturn c.json({\n\t\t\t\titems: asRecords,\n\t\t\t\tpagination: {\n\t\t\t\t\tlimit,\n\t\t\t\t\toffset,\n\t\t\t\t\tnext_offset: hasMore ? offset + result.length : null,\n\t\t\t\t\thas_more: hasMore,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\t});\n\n\t// GET /api/session (aggregate counts)\n\tapp.get(\"/api/session\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst project = c.req.query(\"project\") || null;\n\t\t\tconst count = (sql: string, ...params: unknown[]): number => {\n\t\t\t\tconst row = store.db.prepare(sql).get(...params) as Record<string, unknown> | undefined;\n\t\t\t\treturn Number(row?.total ?? 0);\n\t\t\t};\n\n\t\t\tlet prompts: number;\n\t\t\tlet artifacts: number;\n\t\t\tlet memories: number;\n\t\t\tlet observations: number;\n\t\t\tconst countObservations = (scopeProject?: string) => {\n\t\t\t\tlet offset = 0;\n\t\t\t\tlet total = 0;\n\t\t\t\twhile (true) {\n\t\t\t\t\tconst page = queryMemoryPage(store, {\n\t\t\t\t\t\tlimit: 200,\n\t\t\t\t\t\toffset,\n\t\t\t\t\t\tproject: scopeProject,\n\t\t\t\t\t});\n\t\t\t\t\tif (page.length === 0) break;\n\t\t\t\t\ttotal += page.filter((item) => !isSummaryLikeMemory(item)).length;\n\t\t\t\t\tif (page.length < 200) break;\n\t\t\t\t\toffset += page.length;\n\t\t\t\t}\n\t\t\t\treturn total;\n\t\t\t};\n\t\t\tif (project) {\n\t\t\t\tprompts = count(\"SELECT COUNT(*) AS total FROM user_prompts WHERE project = ?\", project);\n\t\t\t\tartifacts = count(\n\t\t\t\t\t`SELECT COUNT(*) AS total FROM artifacts\n\t\t\t\t\t JOIN sessions ON sessions.id = artifacts.session_id\n\t\t\t\t\t WHERE sessions.project = ?`,\n\t\t\t\t\tproject,\n\t\t\t\t);\n\t\t\t\tmemories = count(\n\t\t\t\t\t`SELECT COUNT(*) AS total FROM memory_items\n\t\t\t\t\t JOIN sessions ON sessions.id = memory_items.session_id\n\t\t\t\t\t WHERE sessions.project = ?`,\n\t\t\t\t\tproject,\n\t\t\t\t);\n\t\t\t\tobservations = countObservations(project);\n\t\t\t} else {\n\t\t\t\tprompts = count(\"SELECT COUNT(*) AS total FROM user_prompts\");\n\t\t\t\tartifacts = count(\"SELECT COUNT(*) AS total FROM artifacts\");\n\t\t\t\tmemories = count(\"SELECT COUNT(*) AS total FROM memory_items\");\n\t\t\t\tobservations = countObservations();\n\t\t\t}\n\t\t\tconst total = prompts + artifacts + memories;\n\t\t\treturn c.json({ total, memories, artifacts, prompts, observations });\n\t\t}\n\t});\n\n\t// GET /api/pack\n\tapp.get(\"/api/pack\", async (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst context = c.req.query(\"context\") || \"\";\n\t\t\tif (!context) {\n\t\t\t\treturn c.json({ error: \"context required\" }, 400);\n\t\t\t}\n\t\t\tconst limit = queryInt(c.req.query(\"limit\"), 10);\n\t\t\tconst tokenBudgetStr = c.req.query(\"token_budget\");\n\t\t\tlet tokenBudget: number | undefined;\n\t\t\tif (tokenBudgetStr) {\n\t\t\t\ttokenBudget = parseStrictInteger(tokenBudgetStr) ?? undefined;\n\t\t\t\tif (tokenBudget === undefined) {\n\t\t\t\t\treturn c.json({ error: \"token_budget must be int\" }, 400);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst project = c.req.query(\"project\") || undefined;\n\t\t\tconst filters: { project?: string } = {};\n\t\t\tif (project) filters.project = project;\n\t\t\tconst pack = await store.buildMemoryPackAsync(context, limit, tokenBudget ?? null, filters);\n\t\t\treturn c.json(pack);\n\t\t}\n\t});\n\n\tapp.post(\"/api/pack/trace\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst parsed = await c.req.json().catch(() => Symbol.for(\"invalid-json\"));\n\t\tif (parsed === Symbol.for(\"invalid-json\")) {\n\t\t\treturn c.json({ error: \"invalid json body\" }, 400);\n\t\t}\n\t\tconst body = parsed as {\n\t\t\tcontext?: unknown;\n\t\t\tlimit?: unknown;\n\t\t\ttoken_budget?: unknown;\n\t\t\tproject?: unknown;\n\t\t\tworking_set_files?: unknown;\n\t\t} | null;\n\t\tconst context = typeof body?.context === \"string\" ? body.context.trim() : \"\";\n\t\tif (!context) {\n\t\t\treturn c.json({ error: \"context required\" }, 400);\n\t\t}\n\t\tconst limit =\n\t\t\tbody?.limit == null\n\t\t\t\t? 10\n\t\t\t\t: typeof body.limit === \"number\" && Number.isInteger(body.limit) && body.limit >= 1\n\t\t\t\t\t? body.limit\n\t\t\t\t\t: null;\n\t\tif (limit == null) {\n\t\t\treturn c.json({ error: \"limit must be a positive int\" }, 400);\n\t\t}\n\t\tlet tokenBudget: number | null = null;\n\t\tif (body?.token_budget != null) {\n\t\t\tif (\n\t\t\t\ttypeof body.token_budget !== \"number\" ||\n\t\t\t\t!Number.isInteger(body.token_budget) ||\n\t\t\t\tbody.token_budget < 0\n\t\t\t) {\n\t\t\t\treturn c.json({ error: \"token_budget must be int\" }, 400);\n\t\t\t}\n\t\t\ttokenBudget = body.token_budget;\n\t\t}\n\t\tconst project = typeof body?.project === \"string\" && body.project.trim() ? body.project : null;\n\t\tif (body?.working_set_files != null && !Array.isArray(body.working_set_files)) {\n\t\t\treturn c.json({ error: \"working_set_files must be an array of strings\" }, 400);\n\t\t}\n\t\tif (\n\t\t\tArray.isArray(body?.working_set_files) &&\n\t\t\tbody.working_set_files.some((value) => typeof value !== \"string\")\n\t\t) {\n\t\t\treturn c.json({ error: \"working_set_files must be an array of strings\" }, 400);\n\t\t}\n\t\tconst workingSetFiles = Array.isArray(body?.working_set_files) ? body.working_set_files : [];\n\t\tconst filters: { project?: string; working_set_paths?: string[] } = {};\n\t\tif (project) filters.project = project;\n\t\tif (workingSetFiles.length > 0) filters.working_set_paths = workingSetFiles;\n\t\tconst trace = await store.buildMemoryPackTraceAsync(context, limit, tokenBudget, filters);\n\t\treturn c.json(trace);\n\t});\n\n\t// GET /api/memory\n\tapp.get(\"/api/memory\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst limit = queryInt(c.req.query(\"limit\"), 20);\n\t\t\tconst kind = c.req.query(\"kind\") || undefined;\n\t\t\tconst project = c.req.query(\"project\") || undefined;\n\t\t\tconst filters: Record<string, unknown> = {};\n\t\t\tif (kind) filters.kind = kind;\n\t\t\tif (project) filters.project = project;\n\t\t\tconst items = store.recent(limit, filters);\n\t\t\tconst asRecords = items as unknown as Record<string, unknown>[];\n\t\t\tattachSessionFields(store, asRecords);\n\t\t\treturn c.json({ items: asRecords });\n\t\t}\n\t});\n\n\t// GET /api/artifacts\n\tapp.get(\"/api/artifacts\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst sessionIdStr = c.req.query(\"session_id\");\n\t\t\tif (!sessionIdStr) {\n\t\t\t\treturn c.json({ error: \"session_id required\" }, 400);\n\t\t\t}\n\t\t\tconst sessionId = parseStrictInteger(sessionIdStr);\n\t\t\tif (sessionId == null) {\n\t\t\t\treturn c.json({ error: \"session_id must be int\" }, 400);\n\t\t\t}\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst rows = d\n\t\t\t\t.select()\n\t\t\t\t.from(schema.artifacts)\n\t\t\t\t.where(eq(schema.artifacts.session_id, sessionId))\n\t\t\t\t.all();\n\t\t\treturn c.json({ items: rows });\n\t\t}\n\t});\n\n\t// POST /api/memories/visibility\n\tapp.post(\"/api/memories/visibility\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid JSON\" }, 400);\n\t\t}\n\t\tconst memoryId = parseStrictInteger(\n\t\t\ttypeof body.memory_id === \"string\" ? body.memory_id : String(body.memory_id ?? \"\"),\n\t\t);\n\t\tif (memoryId == null || memoryId <= 0) {\n\t\t\treturn c.json({ error: \"memory_id must be int\" }, 400);\n\t\t}\n\t\tconst visibility = String(body.visibility ?? \"\").trim();\n\t\tif (visibility !== \"private\" && visibility !== \"shared\") {\n\t\t\treturn c.json({ error: \"visibility must be private or shared\" }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst item = store.updateMemoryVisibility(memoryId, visibility);\n\t\t\treturn c.json({ item });\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\tif (msg.includes(\"not found\")) return c.json({ error: msg }, 404);\n\t\t\tif (msg.includes(\"not owned\")) return c.json({ error: msg }, 403);\n\t\t\treturn c.json({ error: msg }, 400);\n\t\t}\n\t});\n\n\t// POST /api/memories/forget\n\tapp.post(\"/api/memories/forget\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid JSON\" }, 400);\n\t\t}\n\t\tconst memoryId = parseStrictInteger(\n\t\t\ttypeof body.memory_id === \"string\" ? body.memory_id : String(body.memory_id ?? \"\"),\n\t\t);\n\t\tif (memoryId == null || memoryId <= 0) {\n\t\t\treturn c.json({ error: \"memory_id must be int\" }, 400);\n\t\t}\n\n\t\tconst row = drizzle(store.db, { schema })\n\t\t\t.select()\n\t\t\t.from(schema.memoryItems)\n\t\t\t.where(eq(schema.memoryItems.id, memoryId))\n\t\t\t.get();\n\t\tif (!row) {\n\t\t\treturn c.json({ error: \"memory not found\" }, 404);\n\t\t}\n\t\tconst ownership = buildOwnershipContext(store);\n\t\tif (!memoryOwnedBySelf(row, ownership)) {\n\t\t\treturn c.json({ error: \"memory not owned by this device\" }, 403);\n\t\t}\n\t\tif (Number(row.active ?? 1) === 0 || row.deleted_at != null) {\n\t\t\treturn c.json({ status: \"ok\" });\n\t\t}\n\n\t\ttry {\n\t\t\tstore.forget(memoryId);\n\t\t\treturn c.json({ status: \"ok\" });\n\t\t} catch (err) {\n\t\t\tconst msg = err instanceof Error ? err.message : String(err);\n\t\t\tif (msg.includes(\"not found\")) return c.json({ error: msg }, 404);\n\t\t\tif (msg.includes(\"not owned\")) return c.json({ error: msg }, 403);\n\t\t\tif (msg.includes(\"sync_rebootstrap_in_progress\")) return c.json({ error: msg }, 409);\n\t\t\treturn c.json({ error: msg }, 400);\n\t\t}\n\t});\n\n\treturn app;\n}\n","/**\n * Observer status route — GET /api/observer-status.\n *\n * Ports Python's viewer_routes/observer_status.py.\n * Returns observer runtime info, credential availability, and queue status.\n */\n\nimport type { ObserverClient } from \"@codemem/core\";\nimport { type MemoryStore, probeAvailableCredentials, type RawEventSweeper } from \"@codemem/core\";\nimport { Hono } from \"hono\";\n\ntype StoreFactory = () => MemoryStore;\n\nexport interface ObserverStatusDeps {\n\tgetStore: StoreFactory;\n\tgetSweeper: () => RawEventSweeper | null;\n\tgetObserver?: () => ObserverClient | null;\n}\n\nfunction normalizeActiveObserver(active: ReturnType<ObserverClient[\"getStatus\"]> | null) {\n\tif (!active) return null;\n\treturn {\n\t\t...active,\n\t\tauth: {\n\t\t\t...active.auth,\n\t\t\tmethod: active.auth.type,\n\t\t\ttoken_present: active.auth.hasToken,\n\t\t},\n\t};\n}\n\nfunction buildFailureImpact(\n\tlatestFailure: Record<string, unknown> | null,\n\tqueueTotals: { pending: number; sessions: number },\n\tauthBackoff: { active: boolean; remainingS: number },\n): string | null {\n\tif (!latestFailure) return null;\n\tif (authBackoff.active) {\n\t\treturn `Queue retries paused for ~${authBackoff.remainingS}s after an observer auth failure.`;\n\t}\n\tif (queueTotals.pending > 0) {\n\t\treturn `${queueTotals.pending} queued raw events across ${queueTotals.sessions} session(s) are waiting on a successful flush.`;\n\t}\n\treturn \"Failed flush batches are pending retry.\";\n}\n\nexport function observerStatusRoutes(deps?: ObserverStatusDeps) {\n\tconst app = new Hono();\n\n\tapp.get(\"/api/observer-status\", (c) => {\n\t\tconst store = deps?.getStore();\n\t\tconst sweeper = deps?.getSweeper();\n\t\tconst observer = deps?.getObserver?.() ?? null;\n\n\t\t// Stub fallback when store doesn't have the required methods (e.g. tests with mock store)\n\t\tif (!store || typeof store.rawEventBacklogTotals !== \"function\") {\n\t\t\treturn c.json({\n\t\t\t\tactive: null,\n\t\t\t\tavailable_credentials: {},\n\t\t\t\tlatest_failure: null,\n\t\t\t\tqueue: {\n\t\t\t\t\tpending: 0,\n\t\t\t\t\tsessions: 0,\n\t\t\t\t\tauth_backoff_active: false,\n\t\t\t\t\tauth_backoff_remaining_s: 0,\n\t\t\t\t},\n\t\t\t});\n\t\t}\n\n\t\tconst queueTotals = store.rawEventBacklogTotals();\n\t\tconst authBackoff = sweeper?.authBackoffStatus() ?? { active: false, remainingS: 0 };\n\t\tconst latestFailure = store.latestRawEventFlushFailure();\n\t\tconst active = normalizeActiveObserver(observer?.getStatus() ?? null);\n\t\tconst availableCredentials = probeAvailableCredentials();\n\t\tconst shouldShowFailure =\n\t\t\tlatestFailure != null && (authBackoff.active || queueTotals.pending > 0);\n\n\t\tconst failureWithImpact =\n\t\t\tshouldShowFailure && latestFailure\n\t\t\t\t? { ...latestFailure, impact: buildFailureImpact(latestFailure, queueTotals, authBackoff) }\n\t\t\t\t: null;\n\n\t\treturn c.json({\n\t\t\tactive,\n\t\t\tavailable_credentials: availableCredentials,\n\t\t\tlatest_failure: failureWithImpact,\n\t\t\tqueue: {\n\t\t\t\t...queueTotals,\n\t\t\t\tauth_backoff_active: authBackoff.active,\n\t\t\t\tauth_backoff_remaining_s: authBackoff.remainingS,\n\t\t\t},\n\t\t});\n\t});\n\n\treturn app;\n}\n","/**\n * Raw events routes — GET & POST /api/raw-events, GET /api/raw-events/status,\n * POST /api/claude-hooks.\n */\n\nimport { createHash } from \"node:crypto\";\nimport type { MemoryStore, RawEventSweeper } from \"@codemem/core\";\nimport { buildRawEventEnvelopeFromHook, schema, stripPrivateObj } from \"@codemem/core\";\nimport { desc } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { Hono } from \"hono\";\nimport { queryInt } from \"../helpers.js\";\n\ntype StoreFactory = () => MemoryStore;\n\nconst MAX_RAW_EVENTS_BODY_BYTES =\n\tNumber.parseInt(process.env.CODEMEM_RAW_EVENTS_MAX_BODY_BYTES ?? \"\", 10) || 1048576;\n\n/** Keys to check (in priority order) when resolving a session stream id. */\nconst SESSION_ID_KEYS = [\n\t\"session_stream_id\",\n\t\"session_id\",\n\t\"stream_id\",\n\t\"opencode_session_id\",\n] as const;\n\n/**\n * Resolve a session stream id from a payload object.\n * Checks multiple field aliases. Throws on conflicting values.\n */\nfunction resolveSessionStreamId(payload: Record<string, unknown>): string | null {\n\tconst values = new Map<string, string>();\n\tfor (const key of SESSION_ID_KEYS) {\n\t\tconst value = payload[key];\n\t\tif (value == null) continue;\n\t\tif (typeof value !== \"string\") throw new Error(`${key} must be string`);\n\t\tconst text = value.trim();\n\t\tif (text) values.set(key, text);\n\t}\n\tif (values.size === 0) return null;\n\tconst unique = new Set(values.values());\n\tif (unique.size > 1) throw new Error(\"conflicting session id fields\");\n\t// Return the first matching key's value (preserves priority order)\n\tfor (const key of SESSION_ID_KEYS) {\n\t\tconst v = values.get(key);\n\t\tif (v) return v;\n\t}\n\treturn null;\n}\n\n/**\n * Parse and validate a JSON object body, enforcing size limits.\n * Returns the parsed payload or a Hono Response on error.\n */\nasync function parseJsonObjectBody(\n\tc: {\n\t\treq: { header: (name: string) => string | undefined; text: () => Promise<string> };\n\t\tjson: (data: unknown, status?: number) => Response;\n\t},\n\tmaxBytes: number,\n): Promise<Record<string, unknown> | Response> {\n\tconst contentLength = Number.parseInt(c.req.header(\"content-length\") ?? \"0\", 10);\n\tif (Number.isNaN(contentLength) || contentLength < 0) {\n\t\treturn c.json({ error: \"invalid content-length\" }, 400);\n\t}\n\tif (contentLength > maxBytes) {\n\t\treturn c.json({ error: \"payload too large\", max_bytes: maxBytes }, 413);\n\t}\n\tlet raw: string;\n\ttry {\n\t\traw = await c.req.text();\n\t} catch {\n\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t}\n\tif (Buffer.byteLength(raw, \"utf-8\") > maxBytes) {\n\t\treturn c.json({ error: \"payload too large\", max_bytes: maxBytes }, 413);\n\t}\n\tlet parsed: unknown;\n\ttry {\n\t\tparsed = raw ? JSON.parse(raw) : {};\n\t} catch {\n\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t}\n\tif (parsed == null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\treturn c.json({ error: \"payload must be an object\" }, 400);\n\t}\n\treturn parsed as Record<string, unknown>;\n}\n\n/** Nudge the sweeper safely — never crashes the caller. */\nfunction nudgeSweeper(\n\tsweeper: RawEventSweeper | null | undefined,\n\tsessionIds: Iterable<string>,\n\tsource = \"opencode\",\n): void {\n\ttry {\n\t\tfor (const sessionId of sessionIds) {\n\t\t\tsweeper?.nudge(sessionId, source);\n\t\t}\n\t} catch {\n\t\t// never crash the request if sweeper nudge fails\n\t}\n}\n\nexport function rawEventsRoutes(getStore: StoreFactory, sweeper?: RawEventSweeper | null) {\n\tconst app = new Hono();\n\n\t// GET /api/raw-events (compat endpoint for stats panel)\n\tapp.get(\"/api/raw-events\", (c) => {\n\t\tconst store = getStore();\n\t\tconst totals = store.rawEventBacklogTotals();\n\t\treturn c.json(totals);\n\t});\n\n\t// GET /api/raw-events/status\n\tapp.get(\"/api/raw-events/status\", (c) => {\n\t\tconst store = getStore();\n\t\tconst limit = queryInt(c.req.query(\"limit\"), 25);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst rows = d\n\t\t\t.select({\n\t\t\t\tsource: schema.rawEventSessions.source,\n\t\t\t\tstream_id: schema.rawEventSessions.stream_id,\n\t\t\t\topencode_session_id: schema.rawEventSessions.opencode_session_id,\n\t\t\t\tcwd: schema.rawEventSessions.cwd,\n\t\t\t\tproject: schema.rawEventSessions.project,\n\t\t\t\tstarted_at: schema.rawEventSessions.started_at,\n\t\t\t\tlast_seen_ts_wall_ms: schema.rawEventSessions.last_seen_ts_wall_ms,\n\t\t\t\tlast_received_event_seq: schema.rawEventSessions.last_received_event_seq,\n\t\t\t\tlast_flushed_event_seq: schema.rawEventSessions.last_flushed_event_seq,\n\t\t\t\tupdated_at: schema.rawEventSessions.updated_at,\n\t\t\t})\n\t\t\t.from(schema.rawEventSessions)\n\t\t\t.orderBy(desc(schema.rawEventSessions.updated_at))\n\t\t\t.limit(limit)\n\t\t\t.all();\n\t\tconst items = rows.map((row) => {\n\t\t\tconst streamId = String(row.stream_id ?? row.opencode_session_id ?? \"\");\n\t\t\treturn {\n\t\t\t\t...row,\n\t\t\t\tsession_stream_id: streamId,\n\t\t\t\tsession_id: streamId,\n\t\t\t};\n\t\t});\n\t\tconst totals = store.rawEventBacklogTotals();\n\t\treturn c.json({\n\t\t\titems,\n\t\t\ttotals,\n\t\t\tingest: {\n\t\t\t\tavailable: true,\n\t\t\t\tmode: \"stream_queue\",\n\t\t\t\tmax_body_bytes: MAX_RAW_EVENTS_BODY_BYTES,\n\t\t\t},\n\t\t});\n\t});\n\n\t// POST /api/raw-events — ingest raw events from plugin\n\tapp.post(\"/api/raw-events\", async (c) => {\n\t\tconst result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);\n\t\tif (result instanceof Response) return result;\n\t\tconst payload = result;\n\n\t\tconst store = getStore();\n\t\ttry {\n\t\t\t// Validate top-level string fields\n\t\t\tconst cwd = payload.cwd;\n\t\t\tif (cwd != null && typeof cwd !== \"string\") {\n\t\t\t\treturn c.json({ error: \"cwd must be string\" }, 400);\n\t\t\t}\n\t\t\tconst project = payload.project;\n\t\t\tif (project != null && typeof project !== \"string\") {\n\t\t\t\treturn c.json({ error: \"project must be string\" }, 400);\n\t\t\t}\n\t\t\tconst startedAt = payload.started_at;\n\t\t\tif (startedAt != null && typeof startedAt !== \"string\") {\n\t\t\t\treturn c.json({ error: \"started_at must be string\" }, 400);\n\t\t\t}\n\n\t\t\t// Determine event list: batch (events array) or single-event payload\n\t\t\tlet items = payload.events;\n\t\t\tif (items == null) {\n\t\t\t\titems = [payload];\n\t\t\t}\n\t\t\tif (!Array.isArray(items)) {\n\t\t\t\treturn c.json({ error: \"events must be a list\" }, 400);\n\t\t\t}\n\n\t\t\t// Resolve default session id from top-level payload\n\t\t\tlet defaultSessionId: string;\n\t\t\ttry {\n\t\t\t\tdefaultSessionId = resolveSessionStreamId(payload) ?? \"\";\n\t\t\t} catch (err) {\n\t\t\t\treturn c.json({ error: (err as Error).message }, 400);\n\t\t\t}\n\t\t\tif (defaultSessionId.startsWith(\"msg_\")) {\n\t\t\t\treturn c.json({ error: \"invalid session id\" }, 400);\n\t\t\t}\n\n\t\t\tlet inserted = 0;\n\t\t\tconst lastSeenBySession = new Map<string, number>();\n\t\t\tconst metaBySession = new Map<string, Record<string, string>>();\n\t\t\tconst sessionIds = new Set<string>();\n\t\t\tconst batchBySession = new Map<string, Record<string, unknown>[]>();\n\n\t\t\tfor (const item of items) {\n\t\t\t\tif (item == null || typeof item !== \"object\" || Array.isArray(item)) {\n\t\t\t\t\treturn c.json({ error: \"event must be an object\" }, 400);\n\t\t\t\t}\n\t\t\t\tconst itemObj = item as Record<string, unknown>;\n\n\t\t\t\tlet itemSessionId: string | null;\n\t\t\t\ttry {\n\t\t\t\t\titemSessionId = resolveSessionStreamId(itemObj);\n\t\t\t\t} catch (err) {\n\t\t\t\t\treturn c.json({ error: (err as Error).message }, 400);\n\t\t\t\t}\n\t\t\t\tconst opencodeSessionId = String(itemSessionId ?? defaultSessionId ?? \"\");\n\t\t\t\tif (!opencodeSessionId) {\n\t\t\t\t\treturn c.json({ error: \"session id required\" }, 400);\n\t\t\t\t}\n\t\t\t\tif (opencodeSessionId.startsWith(\"msg_\")) {\n\t\t\t\t\treturn c.json({ error: \"invalid session id\" }, 400);\n\t\t\t\t}\n\n\t\t\t\tlet eventId = String(itemObj.event_id ?? \"\");\n\t\t\t\tconst eventType = String(itemObj.event_type ?? \"\");\n\t\t\t\tif (!eventType) {\n\t\t\t\t\treturn c.json({ error: \"event_type required\" }, 400);\n\t\t\t\t}\n\n\t\t\t\tconst eventSeqValue = itemObj.event_seq;\n\t\t\t\tif (eventSeqValue != null) {\n\t\t\t\t\tconst parsed = Number(eventSeqValue);\n\t\t\t\t\tif (!Number.isFinite(parsed) || parsed !== Math.floor(parsed)) {\n\t\t\t\t\t\treturn c.json({ error: \"event_seq must be int\" }, 400);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tlet tsWallMs = itemObj.ts_wall_ms;\n\t\t\t\tif (tsWallMs != null) {\n\t\t\t\t\tconst parsed = Number(tsWallMs);\n\t\t\t\t\tif (!Number.isFinite(parsed)) {\n\t\t\t\t\t\treturn c.json({ error: \"ts_wall_ms must be int\" }, 400);\n\t\t\t\t\t}\n\t\t\t\t\ttsWallMs = Math.floor(parsed);\n\t\t\t\t\tconst prev = lastSeenBySession.get(opencodeSessionId) ?? (tsWallMs as number);\n\t\t\t\t\tlastSeenBySession.set(opencodeSessionId, Math.max(prev, tsWallMs as number));\n\t\t\t\t}\n\n\t\t\t\tlet tsMonoMs = itemObj.ts_mono_ms;\n\t\t\t\tif (tsMonoMs != null) {\n\t\t\t\t\tconst parsed = Number(tsMonoMs);\n\t\t\t\t\tif (!Number.isFinite(parsed)) {\n\t\t\t\t\t\treturn c.json({ error: \"ts_mono_ms must be number\" }, 400);\n\t\t\t\t\t}\n\t\t\t\t\ttsMonoMs = parsed;\n\t\t\t\t}\n\n\t\t\t\tlet eventPayload = itemObj.payload;\n\t\t\t\tif (eventPayload == null) eventPayload = {};\n\t\t\t\tif (typeof eventPayload !== \"object\" || Array.isArray(eventPayload)) {\n\t\t\t\t\treturn c.json({ error: \"payload must be an object\" }, 400);\n\t\t\t\t}\n\n\t\t\t\t// Per-item meta fields\n\t\t\t\tconst itemCwd = itemObj.cwd;\n\t\t\t\tif (itemCwd != null && typeof itemCwd !== \"string\") {\n\t\t\t\t\treturn c.json({ error: \"cwd must be string\" }, 400);\n\t\t\t\t}\n\t\t\t\tconst itemProject = itemObj.project;\n\t\t\t\tif (itemProject != null && typeof itemProject !== \"string\") {\n\t\t\t\t\treturn c.json({ error: \"project must be string\" }, 400);\n\t\t\t\t}\n\t\t\t\tconst itemStartedAt = itemObj.started_at;\n\t\t\t\tif (itemStartedAt != null && typeof itemStartedAt !== \"string\") {\n\t\t\t\t\treturn c.json({ error: \"started_at must be string\" }, 400);\n\t\t\t\t}\n\n\t\t\t\t// Sanitize payload\n\t\t\t\teventPayload = stripPrivateObj(eventPayload) as Record<string, unknown>;\n\n\t\t\t\t// Generate stable event_id for legacy senders.\n\t\t\t\t// Python uses json.dumps(sort_keys=True) which recursively sorts all keys.\n\t\t\t\t// We replicate with a recursive key-sorting replacer.\n\t\t\t\tif (!eventId) {\n\t\t\t\t\tconst sortedStringify = (obj: unknown): string =>\n\t\t\t\t\t\tJSON.stringify(obj, (_key, value) => {\n\t\t\t\t\t\t\tif (value != null && typeof value === \"object\" && !Array.isArray(value)) {\n\t\t\t\t\t\t\t\tconst sorted: Record<string, unknown> = {};\n\t\t\t\t\t\t\t\tfor (const k of Object.keys(value as Record<string, unknown>).sort()) {\n\t\t\t\t\t\t\t\t\tsorted[k] = (value as Record<string, unknown>)[k];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\treturn sorted;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\treturn value;\n\t\t\t\t\t\t});\n\t\t\t\t\tif (eventSeqValue != null) {\n\t\t\t\t\t\tconst rawId = sortedStringify({\n\t\t\t\t\t\t\ts: eventSeqValue,\n\t\t\t\t\t\t\tt: eventType,\n\t\t\t\t\t\t\tp: eventPayload,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconst hash = createHash(\"sha256\").update(rawId, \"utf-8\").digest(\"hex\").slice(0, 16);\n\t\t\t\t\t\teventId = `legacy-seq-${eventSeqValue}-${hash}`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tconst rawId = sortedStringify({\n\t\t\t\t\t\t\tm: tsMonoMs ?? null,\n\t\t\t\t\t\t\tp: eventPayload,\n\t\t\t\t\t\t\tt: eventType,\n\t\t\t\t\t\t\tw: tsWallMs ?? null,\n\t\t\t\t\t\t});\n\t\t\t\t\t\teventId = `legacy-${createHash(\"sha256\").update(rawId, \"utf-8\").digest(\"hex\").slice(0, 16)}`;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst eventEntry: Record<string, unknown> = {\n\t\t\t\t\tevent_id: eventId,\n\t\t\t\t\tevent_type: eventType,\n\t\t\t\t\tpayload: eventPayload,\n\t\t\t\t\tts_wall_ms: tsWallMs ?? null,\n\t\t\t\t\tts_mono_ms: tsMonoMs ?? null,\n\t\t\t\t};\n\n\t\t\t\tsessionIds.add(opencodeSessionId);\n\t\t\t\tconst list = batchBySession.get(opencodeSessionId) ?? [];\n\t\t\t\tlist.push({ ...eventEntry });\n\t\t\t\tbatchBySession.set(opencodeSessionId, list);\n\n\t\t\t\tif (itemCwd || itemProject || itemStartedAt) {\n\t\t\t\t\tconst perSession = metaBySession.get(opencodeSessionId) ?? {};\n\t\t\t\t\tif (itemCwd) perSession.cwd = itemCwd as string;\n\t\t\t\t\tif (itemProject) perSession.project = itemProject as string;\n\t\t\t\t\tif (itemStartedAt) perSession.started_at = itemStartedAt as string;\n\t\t\t\t\tmetaBySession.set(opencodeSessionId, perSession);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Insert events\n\t\t\tif (sessionIds.size === 1) {\n\t\t\t\tconst singleSessionId = sessionIds.values().next().value as string;\n\t\t\t\tconst batch = batchBySession.get(singleSessionId) ?? [];\n\t\t\t\tconst result = store.recordRawEventsBatch(singleSessionId, batch);\n\t\t\t\tinserted = result.inserted;\n\t\t\t} else {\n\t\t\t\tfor (const [sid, sidEvents] of batchBySession) {\n\t\t\t\t\tconst result = store.recordRawEventsBatch(sid, sidEvents);\n\t\t\t\t\tinserted += result.inserted;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// Update session metadata\n\t\t\tfor (const metaSessionId of sessionIds) {\n\t\t\t\tconst sessionMeta = metaBySession.get(metaSessionId) ?? {};\n\t\t\t\tconst applyRequestMeta = sessionIds.size === 1 || metaSessionId === defaultSessionId;\n\t\t\t\tstore.updateRawEventSessionMeta({\n\t\t\t\t\topencodeSessionId: metaSessionId,\n\t\t\t\t\tcwd:\n\t\t\t\t\t\tsessionMeta.cwd ?? (applyRequestMeta ? (cwd as string | undefined) : undefined) ?? null,\n\t\t\t\t\tproject:\n\t\t\t\t\t\tsessionMeta.project ??\n\t\t\t\t\t\t(applyRequestMeta ? (project as string | undefined) : undefined) ??\n\t\t\t\t\t\tnull,\n\t\t\t\t\tstartedAt:\n\t\t\t\t\t\tsessionMeta.started_at ??\n\t\t\t\t\t\t(applyRequestMeta ? (startedAt as string | undefined) : undefined) ??\n\t\t\t\t\t\tnull,\n\t\t\t\t\tlastSeenTsWallMs: lastSeenBySession.get(metaSessionId) ?? null,\n\t\t\t\t});\n\t\t\t}\n\n\t\t\t// Note per-session activity for optional debounced auto-flush.\n\t\t\tnudgeSweeper(sweeper, sessionIds);\n\n\t\t\treturn c.json({ inserted, received: (items as unknown[]).length });\n\t\t} catch (err) {\n\t\t\tconst response: Record<string, unknown> = { error: \"internal server error\" };\n\t\t\tif (process.env.CODEMEM_VIEWER_DEBUG === \"1\") {\n\t\t\t\tresponse.detail = (err as Error).message;\n\t\t\t}\n\t\t\treturn c.json(response, 500);\n\t\t}\n\t});\n\n\t// POST /api/claude-hooks — ingest Claude Code hook events\n\tapp.post(\"/api/claude-hooks\", async (c) => {\n\t\tconst result = await parseJsonObjectBody(c, MAX_RAW_EVENTS_BODY_BYTES);\n\t\tif (result instanceof Response) return result;\n\t\tconst payload = result;\n\n\t\t// Map hook payload → raw event envelope\n\t\tconst envelope = buildRawEventEnvelopeFromHook(payload);\n\t\tif (envelope === null) {\n\t\t\t// Unsupported event type or missing required fields — skip gracefully\n\t\t\treturn c.json({ inserted: 0, skipped: 1 });\n\t\t}\n\n\t\tconst store = getStore();\n\t\ttry {\n\t\t\tconst opencodeSessionId = envelope.opencode_session_id;\n\t\t\tconst source = envelope.source;\n\t\t\tconst strippedPayload = stripPrivateObj(envelope.payload) as Record<string, unknown>;\n\n\t\t\tconst inserted = store.recordRawEvent({\n\t\t\t\topencodeSessionId,\n\t\t\t\tsource,\n\t\t\t\teventId: envelope.event_id,\n\t\t\t\teventType: \"claude.hook\",\n\t\t\t\tpayload: strippedPayload,\n\t\t\t\ttsWallMs: envelope.ts_wall_ms,\n\t\t\t});\n\n\t\t\tstore.updateRawEventSessionMeta({\n\t\t\t\topencodeSessionId,\n\t\t\t\tsource,\n\t\t\t\tcwd: envelope.cwd,\n\t\t\t\tproject: envelope.project,\n\t\t\t\tstartedAt: envelope.started_at,\n\t\t\t\tlastSeenTsWallMs: envelope.ts_wall_ms,\n\t\t\t});\n\n\t\t\t// Note activity for optional debounced auto-flush.\n\t\t\tnudgeSweeper(sweeper, [opencodeSessionId], source);\n\n\t\t\treturn c.json({ inserted: inserted ? 1 : 0, skipped: 0 });\n\t\t} catch (err) {\n\t\t\tconst response: Record<string, unknown> = { error: \"internal server error\" };\n\t\t\tif (process.env.CODEMEM_VIEWER_DEBUG === \"1\") {\n\t\t\t\tresponse.detail = (err as Error).message;\n\t\t\t}\n\t\t\treturn c.json(response, 500);\n\t\t}\n\t});\n\n\treturn app;\n}\n","/**\n * Stats routes — GET /api/stats, GET /api/usage.\n *\n * Ports Python's viewer_routes/stats.py.\n */\n\nimport { listMaintenanceJobs, type MemoryStore, VERSION } from \"@codemem/core\";\nimport { Hono } from \"hono\";\n\nfunction maintenanceJobSortKey(job: {\n\tstarted_at: string | null;\n\tupdated_at: string;\n\tkind: string;\n}): [string, string] {\n\treturn [job.started_at ?? job.updated_at, job.kind];\n}\n\nfunction sortActiveMaintenanceJobs<\n\tT extends { started_at: string | null; updated_at: string; kind: string },\n>(jobs: T[]): T[] {\n\treturn [...jobs].sort((a, b) => {\n\t\tconst [aTime, aKind] = maintenanceJobSortKey(a);\n\t\tconst [bTime, bKind] = maintenanceJobSortKey(b);\n\t\tif (aTime !== bTime) return aTime.localeCompare(bTime);\n\t\treturn aKind.localeCompare(bKind);\n\t});\n}\n\n/**\n * Create stats routes. The store factory is called per-request to get a\n * fresh connection (matching the Python viewer pattern).\n */\nexport function statsRoutes(getStore: () => MemoryStore) {\n\tconst app = new Hono();\n\n\tconst parseMetadataJson = (value: unknown): Record<string, unknown> | null => {\n\t\tif (typeof value !== \"string\" || !value.trim()) return null;\n\t\ttry {\n\t\t\treturn JSON.parse(value) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t};\n\n\tapp.get(\"/api/stats\", (c) => {\n\t\tconst store = getStore();\n\t\tconst jobs = listMaintenanceJobs(store.db);\n\t\tconst activeJobs = sortActiveMaintenanceJobs(\n\t\t\tjobs.filter(\n\t\t\t\t(job) => job.status === \"pending\" || job.status === \"running\" || job.status === \"failed\",\n\t\t\t),\n\t\t).map((job) => ({\n\t\t\tkind: job.kind,\n\t\t\ttitle: job.title,\n\t\t\tstatus: job.status,\n\t\t\tmessage: job.message,\n\t\t\tprogress: job.progress,\n\t\t\terror: job.error,\n\t\t}));\n\t\treturn c.json({\n\t\t\t...store.stats(),\n\t\t\tviewer_pid: process.pid,\n\t\t\tmaintenance_jobs: activeJobs,\n\t\t});\n\t});\n\n\tapp.get(\"/api/runtime\", (c) => {\n\t\treturn c.json({\n\t\t\tversion: VERSION,\n\t\t});\n\t});\n\n\tapp.get(\"/api/usage\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst projectFilter = c.req.query(\"project\") || null;\n\t\t\tconst recentPacksQuery = projectFilter\n\t\t\t\t? store.db.prepare(\n\t\t\t\t\t\t`SELECT usage_events.id, usage_events.session_id, usage_events.event,\n\t\t\t\t\t\tusage_events.tokens_read, usage_events.tokens_written, usage_events.tokens_saved,\n\t\t\t\t\t\tusage_events.created_at, usage_events.metadata_json\n\t\t\t\t\t FROM usage_events\n\t\t\t\t\t JOIN sessions ON sessions.id = usage_events.session_id\n\t\t\t\t\t WHERE usage_events.event = 'pack' AND sessions.project = ?\n\t\t\t\t\t ORDER BY usage_events.created_at DESC\n\t\t\t\t\t LIMIT 10`,\n\t\t\t\t\t)\n\t\t\t\t: store.db.prepare(\n\t\t\t\t\t\t`SELECT id, session_id, event, tokens_read, tokens_written, tokens_saved, created_at, metadata_json\n\t\t\t\t\t FROM usage_events\n\t\t\t\t\t WHERE event = 'pack'\n\t\t\t\t\t ORDER BY created_at DESC\n\t\t\t\t\t LIMIT 10`,\n\t\t\t\t\t);\n\t\t\tconst eventsGlobal = store.db\n\t\t\t\t.prepare(\n\t\t\t\t\t`SELECT event,\n\t\t\t\t\t\tSUM(tokens_read) AS total_tokens_read,\n\t\t\t\t\t\tSUM(tokens_written) AS total_tokens_written,\n\t\t\t\t\t\tSUM(tokens_saved) AS total_tokens_saved,\n\t\t\t\t\t\tCOUNT(*) AS count\n\t\t\t\t\t FROM usage_events GROUP BY event ORDER BY event`,\n\t\t\t\t)\n\t\t\t\t.all() as Record<string, unknown>[];\n\t\t\tconst totalsGlobal = store.db\n\t\t\t\t.prepare(\n\t\t\t\t\t`SELECT COALESCE(SUM(tokens_read),0) AS tokens_read,\n\t\t\t\t\t\tCOALESCE(SUM(tokens_written),0) AS tokens_written,\n\t\t\t\t\t\tCOALESCE(SUM(tokens_saved),0) AS tokens_saved,\n\t\t\t\t\t\tCOUNT(*) AS count\n\t\t\t\t\t FROM usage_events`,\n\t\t\t\t)\n\t\t\t\t.get() as Record<string, unknown>;\n\t\t\tlet eventsFiltered: Record<string, unknown>[] | null = null;\n\t\t\tlet totalsFiltered: Record<string, unknown> | null = null;\n\t\t\tif (projectFilter) {\n\t\t\t\teventsFiltered = store.db\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t`SELECT event,\n\t\t\t\t\t\t\tSUM(tokens_read) AS total_tokens_read,\n\t\t\t\t\t\t\tSUM(tokens_written) AS total_tokens_written,\n\t\t\t\t\t\t\tSUM(tokens_saved) AS total_tokens_saved,\n\t\t\t\t\t\t\tCOUNT(*) AS count\n\t\t\t\t\t\t FROM usage_events\n\t\t\t\t\t\t JOIN sessions ON sessions.id = usage_events.session_id\n\t\t\t\t\t\t WHERE sessions.project = ?\n\t\t\t\t\t\t GROUP BY event ORDER BY event`,\n\t\t\t\t\t)\n\t\t\t\t\t.all(projectFilter) as Record<string, unknown>[];\n\t\t\t\ttotalsFiltered = store.db\n\t\t\t\t\t.prepare(\n\t\t\t\t\t\t`SELECT COALESCE(SUM(tokens_read),0) AS tokens_read,\n\t\t\t\t\t\t\tCOALESCE(SUM(tokens_written),0) AS tokens_written,\n\t\t\t\t\t\t\tCOALESCE(SUM(tokens_saved),0) AS tokens_saved,\n\t\t\t\t\t\t\tCOUNT(*) AS count\n\t\t\t\t\t\t FROM usage_events\n\t\t\t\t\t\t JOIN sessions ON sessions.id = usage_events.session_id\n\t\t\t\t\t\t WHERE sessions.project = ?`,\n\t\t\t\t\t)\n\t\t\t\t\t.get(projectFilter) as Record<string, unknown>;\n\t\t\t}\n\t\t\tconst recentPacksRaw = (\n\t\t\t\tprojectFilter ? recentPacksQuery.all(projectFilter) : recentPacksQuery.all()\n\t\t\t) as Record<string, unknown>[];\n\t\t\tconst recentPacks = recentPacksRaw.map((row) => ({\n\t\t\t\tid: Number(row.id ?? 0),\n\t\t\t\tsession_id: row.session_id == null ? null : Number(row.session_id),\n\t\t\t\tevent: String(row.event ?? \"pack\"),\n\t\t\t\ttokens_read: Number(row.tokens_read ?? 0),\n\t\t\t\ttokens_written: Number(row.tokens_written ?? 0),\n\t\t\t\ttokens_saved: Number(row.tokens_saved ?? 0),\n\t\t\t\tcreated_at: String(row.created_at ?? \"\"),\n\t\t\t\tmetadata_json: parseMetadataJson(row.metadata_json),\n\t\t\t}));\n\n\t\t\treturn c.json({\n\t\t\t\tproject: projectFilter,\n\t\t\t\tevents: projectFilter ? eventsFiltered : eventsGlobal,\n\t\t\t\ttotals: projectFilter ? totalsFiltered : totalsGlobal,\n\t\t\t\tevents_global: eventsGlobal,\n\t\t\t\ttotals_global: totalsGlobal,\n\t\t\t\tevents_filtered: eventsFiltered,\n\t\t\t\ttotals_filtered: totalsFiltered,\n\t\t\t\trecent_packs: recentPacks,\n\t\t\t});\n\t\t}\n\t});\n\n\treturn app;\n}\n","/**\n * Sync routes — status, peers, actors, attempts, pairing, mutations.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { readFileSync } from \"node:fs\";\nimport net from \"node:net\";\nimport { networkInterfaces } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type {\n\tCoordinatorBootstrapGrantVerification,\n\tMaintenanceJobSnapshot,\n\tMemoryStore,\n\tReplicationOp,\n\tSemanticIndexDiagnostics,\n} from \"@codemem/core\";\nimport {\n\tapplyReplicationOps,\n\tbuildBaseUrl,\n\tcleanupNonces,\n\tcoordinatorArchiveGroupAction,\n\tcoordinatorCreateGroupAction,\n\tcoordinatorCreateInviteAction,\n\tcoordinatorDisableDeviceAction,\n\tcoordinatorImportInviteAction,\n\tcoordinatorListBootstrapGrantsAction,\n\tcoordinatorListDevicesAction,\n\tcoordinatorListGroupsAction,\n\tcoordinatorListJoinRequestsAction,\n\tcoordinatorRemoveDeviceAction,\n\tcoordinatorRenameDeviceAction,\n\tcoordinatorRenameGroupAction,\n\tcoordinatorReviewJoinRequestAction,\n\tcoordinatorRevokeBootstrapGrantAction,\n\tcoordinatorStatusSnapshot,\n\tcoordinatorUnarchiveGroupAction,\n\tcreateCoordinatorReciprocalApproval,\n\tDEFAULT_TIME_WINDOW_S,\n\tensureDeviceIdentity,\n\textractReplicationOps,\n\tfingerprintPublicKey,\n\tgetSemanticIndexDiagnostics,\n\tgetSyncResetState,\n\tlistCoordinatorJoinRequests,\n\tlistMaintenanceJobs,\n\tloadMemorySnapshotPageForPeer,\n\tloadReplicationOpsForPeer,\n\tlookupCoordinatorPeers,\n\tmergeAddresses,\n\treadCoordinatorSyncConfig,\n\trecordNonce,\n\trequestJson,\n\trunSyncPass,\n\tschema,\n\tsyncProjectAllowedByFilters,\n\tsyncVisibilityAllowed,\n\tverifySignature,\n} from \"@codemem/core\";\nimport { and, count, desc, eq, max, ne } from \"drizzle-orm\";\nimport { drizzle } from \"drizzle-orm/better-sqlite3\";\nimport { type Context, Hono } from \"hono\";\nimport { queryBool, queryInt, safeJsonList } from \"../helpers.js\";\nimport type { InMemoryRequestRateLimiter } from \"../request-rate-limit.js\";\n\ntype StoreFactory = () => MemoryStore;\ntype SyncRuntimeStatus = {\n\tphase:\n\t\t| \"starting\"\n\t\t| \"running\"\n\t\t| \"stopping\"\n\t\t| \"error\"\n\t\t| \"disabled\"\n\t\t| \"rebootstrapping\"\n\t\t| \"needs_attention\"\n\t\t| null;\n\tdetail?: string | null;\n};\n\ninterface SyncProtocolRouteOptions {\n\trouteRateLimit?: {\n\t\tlimiter: InMemoryRequestRateLimiter;\n\t\treadLimit: number;\n\t\tmutationLimit: number;\n\t\tunauthenticatedReadLimit: number;\n\t\tunauthenticatedMutationLimit: number;\n\t};\n}\n\nconst SYNC_STALE_AFTER_SECONDS = 10 * 60;\nconst SYNC_PROTOCOL_VERSION = \"2\";\nconst LEGACY_SYNC_ACTOR_DISPLAY_NAME = \"Legacy synced peer\";\nconst LEGACY_SHARED_WORKSPACE_ID = \"shared:legacy\";\n\ntype CoordinatorAdminReadiness = \"not_configured\" | \"partial\" | \"ready\";\n\nfunction coordinatorAdminStatusPayload(config = readCoordinatorSyncConfig()) {\n\tconst groups = config.syncCoordinatorGroups;\n\tconst activeGroup = groups[0] ?? null;\n\tconst hasUrl = Boolean(config.syncCoordinatorUrl);\n\tconst hasGroups = groups.length > 0;\n\tconst hasAdminSecret = Boolean(config.syncCoordinatorAdminSecret);\n\tlet readiness: CoordinatorAdminReadiness = \"ready\";\n\tif (!hasUrl) readiness = \"not_configured\";\n\telse if (!hasGroups || !hasAdminSecret) readiness = \"partial\";\n\treturn {\n\t\treadiness,\n\t\tcoordinator_url: config.syncCoordinatorUrl || null,\n\t\tgroups,\n\t\tactive_group: activeGroup,\n\t\thas_admin_secret: hasAdminSecret,\n\t\thas_groups: hasGroups,\n\t};\n}\n\nfunction pairingAdvertiseAddresses(config = readCoordinatorSyncConfig()): string[] {\n\tconst advertise = String(config.syncAdvertise || \"auto\")\n\t\t.trim()\n\t\t.toLowerCase();\n\tif (advertise && advertise !== \"auto\" && advertise !== \"default\") {\n\t\treturn mergeAddresses(\n\t\t\t[],\n\t\t\tString(config.syncAdvertise || \"\")\n\t\t\t\t.split(\",\")\n\t\t\t\t.map((item) => item.trim())\n\t\t\t\t.filter(Boolean),\n\t\t);\n\t}\n\tif (config.syncHost && config.syncHost !== \"0.0.0.0\") {\n\t\treturn [`${config.syncHost}:${config.syncPort}`];\n\t}\n\tconst addresses = Object.values(networkInterfaces())\n\t\t.flatMap((entries) => entries ?? [])\n\t\t.filter((entry) => !entry.internal)\n\t\t.map((entry) => entry.address)\n\t\t.filter((address) => address && address !== \"127.0.0.1\" && address !== \"::1\")\n\t\t.map((address) => `${address}:${config.syncPort}`);\n\treturn [...new Set(addresses)];\n}\n\nfunction resolveCoordinatorAdminGroup(\n\trequestedGroup: string | null | undefined,\n\tstatus: ReturnType<typeof coordinatorAdminStatusPayload>,\n): string | null {\n\tconst explicit = String(requestedGroup ?? \"\").trim();\n\tif (explicit) return explicit;\n\treturn status.active_group;\n}\n\nfunction parseInviteTtlHours(value: unknown): number | null {\n\tconst ttlHours = Number(String(value ?? 24));\n\tif (!Number.isInteger(ttlHours) || ttlHours < 1) return null;\n\treturn ttlHours;\n}\n\nfunction sortActiveMaintenanceJobs<\n\tT extends { started_at: string | null; updated_at: string; kind: string },\n>(jobs: T[]): T[] {\n\treturn [...jobs].sort((a, b) => {\n\t\tconst aTime = a.started_at ?? a.updated_at;\n\t\tconst bTime = b.started_at ?? b.updated_at;\n\t\tif (aTime !== bTime) return aTime.localeCompare(bTime);\n\t\treturn a.kind.localeCompare(b.kind);\n\t});\n}\n\nfunction summarizeMaintenanceJobs(\n\tjobs: MaintenanceJobSnapshot[],\n\tshowDiagnostics: boolean,\n): Array<Record<string, unknown>> {\n\treturn sortActiveMaintenanceJobs(\n\t\tjobs.filter((job) => [\"pending\", \"running\", \"failed\"].includes(String(job.status ?? \"\"))),\n\t).map((job) => ({\n\t\tkind: job.kind,\n\t\ttitle: job.title,\n\t\tstatus: job.status,\n\t\tprogress: job.progress,\n\t\t...(showDiagnostics\n\t\t\t? {\n\t\t\t\t\tmessage: job.message,\n\t\t\t\t\terror: job.error,\n\t\t\t\t\tmetadata: job.metadata,\n\t\t\t\t}\n\t\t\t: {}),\n\t}));\n}\n\nfunction redactSemanticIndexDiagnostics(\n\tdiagnostics: SemanticIndexDiagnostics,\n\tshowDiagnostics: boolean,\n): SemanticIndexDiagnostics {\n\tif (showDiagnostics || !diagnostics.maintenance_job) {\n\t\treturn diagnostics;\n\t}\n\tconst summary =\n\t\tdiagnostics.state === \"pending\"\n\t\t\t? \"Semantic-index catch-up is pending\"\n\t\t\t: diagnostics.state === \"failed\"\n\t\t\t\t? \"Semantic-index catch-up failed\"\n\t\t\t\t: diagnostics.state === \"degraded\"\n\t\t\t\t\t? \"Semantic index is running in degraded mode\"\n\t\t\t\t\t: diagnostics.summary;\n\treturn {\n\t\t...diagnostics,\n\t\tsummary,\n\t\tmaintenance_job: {\n\t\t\t...diagnostics.maintenance_job,\n\t\t\tmessage: null,\n\t\t\terror: null,\n\t\t},\n\t};\n}\n\nfunction syncKeysDir(): string | undefined {\n\treturn process.env.CODEMEM_KEYS_DIR?.trim() || undefined;\n}\n\nfunction intEnvOr(name: string, fallback: number): number {\n\tconst value = Number.parseInt(process.env[name] ?? \"\", 10);\n\treturn Number.isFinite(value) ? value : fallback;\n}\n\nconst MAX_SYNC_BODY_BYTES = intEnvOr(\"CODEMEM_SYNC_MAX_BODY_BYTES\", 1_048_576);\nconst MAX_SYNC_OPS = intEnvOr(\"CODEMEM_SYNC_MAX_OPS\", 2000);\n\nasync function readBoundedRequestBytes(request: Request, maxBytes: number): Promise<Buffer | null> {\n\tconst contentLength = Number.parseInt(request.headers.get(\"content-length\") ?? \"\", 10);\n\tif (Number.isFinite(contentLength) && contentLength > maxBytes) {\n\t\treturn null;\n\t}\n\tconst stream = request.body;\n\tif (!stream) return Buffer.alloc(0);\n\tconst reader = stream.getReader();\n\tconst chunks: Uint8Array[] = [];\n\tlet total = 0;\n\ttry {\n\t\twhile (true) {\n\t\t\tconst { done, value } = await reader.read();\n\t\t\tif (done) break;\n\t\t\tif (!value) continue;\n\t\t\ttotal += value.byteLength;\n\t\t\tif (total > maxBytes) {\n\t\t\t\tawait reader.cancel();\n\t\t\t\treturn null;\n\t\t\t}\n\t\t\tchunks.push(value);\n\t\t}\n\t} finally {\n\t\treader.releaseLock();\n\t}\n\treturn Buffer.concat(chunks.map((chunk) => Buffer.from(chunk)));\n}\n\nconst PAIRING_FILTER_HINT =\n\t\"Run this on another device with codemem sync pair --accept '<payload>'. \" +\n\t\"On the accepting device, --include/--exclude control both what it sends and what it accepts from that peer.\";\n\nfunction pathWithQuery(url: string): string {\n\tconst parsed = new URL(url);\n\treturn parsed.search ? `${parsed.pathname}${parsed.search}` : parsed.pathname;\n}\n\nfunction unauthorizedPayload(reason: string, exposeReason = false): Record<string, string> {\n\tif (exposeReason && process.env.CODEMEM_SYNC_AUTH_DIAGNOSTICS === \"1\") {\n\t\treturn { error: \"unauthorized\", reason };\n\t}\n\treturn { error: \"unauthorized\" };\n}\n\nfunction authorizeSyncRequest(\n\tstore: MemoryStore,\n\trequest: { method: string; url: string; header(name: string): string | undefined },\n\tbody: Buffer,\n): { ok: boolean; reason: string; deviceId: string } {\n\tconst deviceId = (request.header(\"X-Opencode-Device\") ?? \"\").trim();\n\tconst signature = request.header(\"X-Opencode-Signature\") ?? \"\";\n\tconst timestamp = request.header(\"X-Opencode-Timestamp\") ?? \"\";\n\tconst nonce = request.header(\"X-Opencode-Nonce\") ?? \"\";\n\tif (!deviceId || !signature || !timestamp || !nonce) {\n\t\treturn { ok: false, reason: \"missing_headers\", deviceId };\n\t}\n\n\tconst peerRow = store.db\n\t\t.prepare(\n\t\t\t\"SELECT pinned_fingerprint, public_key FROM sync_peers WHERE peer_device_id = ? LIMIT 1\",\n\t\t)\n\t\t.get(deviceId) as { pinned_fingerprint: string | null; public_key: string | null } | undefined;\n\tif (!peerRow) {\n\t\treturn { ok: false, reason: \"unknown_peer\", deviceId };\n\t}\n\n\tconst pinnedFingerprint = String(peerRow.pinned_fingerprint ?? \"\").trim();\n\tconst publicKey = String(peerRow.public_key ?? \"\").trim();\n\tif (!pinnedFingerprint || !publicKey) {\n\t\treturn { ok: false, reason: \"peer_record_incomplete\", deviceId };\n\t}\n\tif (fingerprintPublicKey(publicKey) !== pinnedFingerprint) {\n\t\treturn { ok: false, reason: \"fingerprint_mismatch\", deviceId };\n\t}\n\n\tlet valid = false;\n\ttry {\n\t\tvalid = verifySignature({\n\t\t\tmethod: request.method,\n\t\t\tpathWithQuery: pathWithQuery(request.url),\n\t\t\tbodyBytes: body,\n\t\t\ttimestamp,\n\t\t\tnonce,\n\t\t\tsignature,\n\t\t\tpublicKey,\n\t\t\tdeviceId,\n\t\t});\n\t} catch {\n\t\treturn { ok: false, reason: \"signature_verification_error\", deviceId };\n\t}\n\n\tif (!valid) {\n\t\treturn { ok: false, reason: \"invalid_signature\", deviceId };\n\t}\n\n\tconst createdAt = new Date().toISOString();\n\tif (!recordNonce(store.db, deviceId, nonce, createdAt)) {\n\t\treturn { ok: false, reason: \"nonce_replay\", deviceId };\n\t}\n\n\tconst cutoff = new Date(Date.now() - DEFAULT_TIME_WINDOW_S * 2 * 1000).toISOString();\n\tcleanupNonces(store.db, cutoff);\n\treturn { ok: true, reason: \"ok\", deviceId };\n}\n\nasync function authorizeBootstrapGrantRequest(\n\tstore: MemoryStore,\n\trequest: { method: string; url: string; header(name: string): string | undefined },\n\tbody: Buffer,\n): Promise<{ ok: boolean; reason: string; deviceId: string }> {\n\tconst grantId = (request.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim();\n\tconst deviceId = (request.header(\"X-Opencode-Device\") ?? \"\").trim();\n\tconst signature = request.header(\"X-Opencode-Signature\") ?? \"\";\n\tconst timestamp = request.header(\"X-Opencode-Timestamp\") ?? \"\";\n\tconst nonce = request.header(\"X-Opencode-Nonce\") ?? \"\";\n\tif (!grantId || !deviceId || !signature || !timestamp || !nonce) {\n\t\treturn { ok: false, reason: \"missing_bootstrap_grant_headers\", deviceId };\n\t}\n\n\tconst config = readCoordinatorSyncConfig();\n\tif (!config.syncCoordinatorUrl || !config.syncCoordinatorAdminSecret) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_coordinator_not_configured\", deviceId };\n\t}\n\n\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\tlet verification: CoordinatorBootstrapGrantVerification;\n\ttry {\n\t\tconst [status, payload] = await requestJson(\n\t\t\t\"GET\",\n\t\t\t`${buildBaseUrl(config.syncCoordinatorUrl)}/v1/admin/bootstrap-grants/${encodeURIComponent(grantId)}`,\n\t\t\t{\n\t\t\t\theaders: { \"X-Codemem-Coordinator-Admin\": config.syncCoordinatorAdminSecret },\n\t\t\t\ttimeoutS: Math.max(1, config.syncCoordinatorTimeoutS),\n\t\t\t},\n\t\t);\n\t\tif (status !== 200 || !payload) {\n\t\t\treturn { ok: false, reason: \"bootstrap_grant_lookup_failed\", deviceId };\n\t\t}\n\t\tverification = payload as unknown as CoordinatorBootstrapGrantVerification;\n\t} catch {\n\t\treturn { ok: false, reason: \"bootstrap_grant_lookup_failed\", deviceId };\n\t}\n\n\tconst grant = verification.grant;\n\tconst workerEnrollment = verification.worker_enrollment;\n\tif (!grant || !workerEnrollment) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_invalid_payload\", deviceId };\n\t}\n\tif (grant.revoked_at) return { ok: false, reason: \"bootstrap_grant_revoked\", deviceId };\n\tif (String(workerEnrollment.device_id) !== String(grant.worker_device_id)) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_worker_enrollment_mismatch\", deviceId };\n\t}\n\tif (String(workerEnrollment.group_id) !== String(grant.group_id)) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_group_mismatch\", deviceId };\n\t}\n\tif (Number(workerEnrollment.enabled) !== 1) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_worker_disabled\", deviceId };\n\t}\n\tif (grant.worker_device_id !== deviceId) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_worker_mismatch\", deviceId };\n\t}\n\tif (grant.seed_device_id !== localDeviceId) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_seed_mismatch\", deviceId };\n\t}\n\tif (new Date(grant.expires_at) <= new Date()) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_expired\", deviceId };\n\t}\n\n\tlet valid = false;\n\ttry {\n\t\tvalid = verifySignature({\n\t\t\tmethod: request.method,\n\t\t\tpathWithQuery: pathWithQuery(request.url),\n\t\t\tbodyBytes: body,\n\t\t\ttimestamp,\n\t\t\tnonce,\n\t\t\tsignature,\n\t\t\tpublicKey: String(workerEnrollment.public_key),\n\t\t\tdeviceId,\n\t\t});\n\t} catch {\n\t\treturn { ok: false, reason: \"bootstrap_grant_signature_verification_error\", deviceId };\n\t}\n\tif (!valid) {\n\t\treturn { ok: false, reason: \"bootstrap_grant_invalid_signature\", deviceId };\n\t}\n\n\tconst createdAt = new Date().toISOString();\n\tif (!recordNonce(store.db, deviceId, nonce, createdAt)) {\n\t\treturn { ok: false, reason: \"nonce_replay\", deviceId };\n\t}\n\tconst cutoff = new Date(Date.now() - DEFAULT_TIME_WINDOW_S * 2 * 1000).toISOString();\n\tcleanupNonces(store.db, cutoff);\n\treturn { ok: true, reason: \"ok\", deviceId };\n}\n\nfunction parseJsonList(value: unknown): string[] {\n\tif (value == null) return [];\n\tif (typeof value === \"string\") {\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(value) as unknown;\n\t\t\tif (!Array.isArray(parsed)) return [];\n\t\t\treturn parsed.map((entry) => String(entry ?? \"\").trim()).filter(Boolean);\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\tif (!Array.isArray(value)) return [];\n\treturn value.map((entry) => String(entry ?? \"\").trim()).filter(Boolean);\n}\n\nfunction readPeerProjectFilters(\n\tstore: MemoryStore,\n\tpeerDeviceId: string,\n): { include: string[]; exclude: string[] } {\n\tconst globalConfig = readCoordinatorSyncConfig();\n\tconst row = store.db\n\t\t.prepare(\n\t\t\t\"SELECT projects_include_json, projects_exclude_json FROM sync_peers WHERE peer_device_id = ? LIMIT 1\",\n\t\t)\n\t\t.get(peerDeviceId) as\n\t\t| { projects_include_json: string | null; projects_exclude_json: string | null }\n\t\t| undefined;\n\tif (!row) {\n\t\treturn {\n\t\t\tinclude: globalConfig.syncProjectsInclude,\n\t\t\texclude: globalConfig.syncProjectsExclude,\n\t\t};\n\t}\n\tconst hasOverride = row.projects_include_json != null || row.projects_exclude_json != null;\n\tif (!hasOverride) {\n\t\treturn {\n\t\t\tinclude: globalConfig.syncProjectsInclude,\n\t\t\texclude: globalConfig.syncProjectsExclude,\n\t\t};\n\t}\n\treturn {\n\t\tinclude: parseJsonList(row.projects_include_json),\n\t\texclude: parseJsonList(row.projects_exclude_json),\n\t};\n}\n\nfunction currentProjectScope(\n\trow: Record<string, unknown>,\n\teffective?: { include: string[]; exclude: string[] },\n): Record<string, unknown> {\n\treturn {\n\t\tinclude: safeJsonList(row.projects_include_json as string | null),\n\t\texclude: safeJsonList(row.projects_exclude_json as string | null),\n\t\teffective_include:\n\t\t\teffective?.include ?? safeJsonList(row.projects_include_json as string | null),\n\t\teffective_exclude:\n\t\t\teffective?.exclude ?? safeJsonList(row.projects_exclude_json as string | null),\n\t\tinherits_global: row.projects_include_json == null && row.projects_exclude_json == null,\n\t};\n}\n\nfunction ensureLocalActorRecord(store: MemoryStore): void {\n\tconst d = drizzle(store.db, { schema });\n\tconst existing = d\n\t\t.select({ actor_id: schema.actors.actor_id })\n\t\t.from(schema.actors)\n\t\t.where(eq(schema.actors.actor_id, store.actorId))\n\t\t.get();\n\tif (existing) return;\n\tconst now = new Date().toISOString();\n\td.insert(schema.actors)\n\t\t.values({\n\t\t\tactor_id: store.actorId,\n\t\t\tdisplay_name: store.actorDisplayName,\n\t\t\tis_local: 1,\n\t\t\tstatus: \"active\",\n\t\t\tmerged_into_actor_id: null,\n\t\t\tcreated_at: now,\n\t\t\tupdated_at: now,\n\t\t})\n\t\t.run();\n}\n\nfunction findPeerDeviceIdForAddress(store: MemoryStore, address: string): string | null {\n\tconst rows = store.db\n\t\t.prepare(\"SELECT peer_device_id, addresses_json FROM sync_peers\")\n\t\t.all() as Array<{ peer_device_id: string; addresses_json: string | null }>;\n\tfor (const row of rows) {\n\t\tconst addresses = safeJsonList(row.addresses_json);\n\t\tif (addresses.includes(address)) return String(row.peer_device_id ?? \"\").trim() || null;\n\t}\n\treturn null;\n}\n\nfunction claimLegacyDeviceAsSelf(store: MemoryStore, originDeviceId: string): number {\n\tconst deviceId = String(originDeviceId || \"\").trim();\n\tif (!deviceId || deviceId === \"unknown\" || deviceId === store.deviceId) return 0;\n\tconst personalWorkspaceId = `personal:${store.actorId}`;\n\tconst result = store.db\n\t\t.prepare(\n\t\t\t`UPDATE memory_items\n\t\t\t SET actor_id = ?,\n\t\t\t actor_display_name = ?,\n\t\t\t visibility = 'private',\n\t\t\t workspace_id = ?,\n\t\t\t workspace_kind = 'personal',\n\t\t\t trust_state = 'trusted'\n\t\t\t WHERE origin_device_id = ?\n\t\t\t AND origin_device_id NOT IN (\n\t\t\t SELECT peer_device_id FROM sync_peers WHERE peer_device_id IS NOT NULL\n\t\t\t )\n\t\t\t AND (\n\t\t\t (\n\t\t\t actor_id IS NULL\n\t\t\t OR TRIM(actor_id) = ''\n\t\t\t OR actor_id LIKE 'legacy-sync:%'\n\t\t\t OR actor_id = ?\n\t\t\t )\n\t\t\t AND (\n\t\t\t actor_id IS NULL\n\t\t\t OR TRIM(actor_id) = ''\n\t\t\t OR actor_id LIKE 'legacy-sync:%'\n\t\t\t OR actor_display_name = ?\n\t\t\t OR workspace_id = ?\n\t\t\t OR trust_state = 'legacy_unknown'\n\t\t\t )\n\t\t\t )`,\n\t\t)\n\t\t.run(\n\t\t\tstore.actorId,\n\t\t\tstore.actorDisplayName,\n\t\t\tpersonalWorkspaceId,\n\t\t\tdeviceId,\n\t\t\tstore.actorId,\n\t\t\tLEGACY_SYNC_ACTOR_DISPLAY_NAME,\n\t\t\tLEGACY_SHARED_WORKSPACE_ID,\n\t\t);\n\treturn Number(result.changes ?? 0);\n}\n\nfunction peerClaimedLocalActor(store: MemoryStore, peerDeviceId: string): boolean {\n\tconst row = store.db\n\t\t.prepare(\"SELECT claimed_local_actor FROM sync_peers WHERE peer_device_id = ? LIMIT 1\")\n\t\t.get(peerDeviceId) as { claimed_local_actor: number | null } | undefined;\n\treturn Boolean(row?.claimed_local_actor);\n}\n\nfunction parseOpPayload(op: { payload_json: string | null }): Record<string, unknown> | null {\n\tif (!op.payload_json || !String(op.payload_json).trim()) return null;\n\ttry {\n\t\tconst parsed = JSON.parse(op.payload_json) as unknown;\n\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) return null;\n\t\treturn parsed as Record<string, unknown>;\n\t} catch {\n\t\treturn null;\n\t}\n}\n\nfunction redactCoordinatorStatus(\n\tcoordinator: Record<string, unknown>,\n\tshowDiag: boolean,\n): Record<string, unknown> {\n\tif (showDiag) return coordinator;\n\tconst discovered = Array.isArray(coordinator.discovered_devices)\n\t\t? coordinator.discovered_devices.map((item) => {\n\t\t\t\tif (!item || typeof item !== \"object\") return item;\n\t\t\t\tconst record = item as Record<string, unknown>;\n\t\t\t\treturn {\n\t\t\t\t\tdevice_id: record.device_id,\n\t\t\t\t\tdisplay_name: record.display_name ?? null,\n\t\t\t\t\tgroups: Array.isArray(record.groups) ? record.groups : [],\n\t\t\t\t\tlast_seen_at: record.last_seen_at ?? null,\n\t\t\t\t\texpires_at: record.expires_at ?? null,\n\t\t\t\t\tstale: Boolean(record.stale),\n\t\t\t\t\tneeds_local_approval: Boolean(record.needs_local_approval),\n\t\t\t\t\twaiting_for_peer_approval: Boolean(record.waiting_for_peer_approval),\n\t\t\t\t\tincoming_reciprocal_request_id: record.incoming_reciprocal_request_id ?? null,\n\t\t\t\t\toutgoing_reciprocal_request_id: record.outgoing_reciprocal_request_id ?? null,\n\t\t\t\t\tfingerprint: null,\n\t\t\t\t\taddresses: [],\n\t\t\t\t};\n\t\t\t})\n\t\t: [];\n\treturn {\n\t\t...coordinator,\n\t\tdiscovered_devices: discovered,\n\t};\n}\n\nasync function acceptDiscoveredPeer(\n\tstore: MemoryStore,\n\tinput: { peerDeviceId: string; fingerprint: string },\n): Promise<\n\t| { ok: true; peer_device_id: string; created: boolean; updated: boolean; name: string | null }\n\t| { ok: false; status: number; error: string; detail: string }\n> {\n\tconst config = readCoordinatorSyncConfig();\n\tif (\n\t\t!config.syncEnabled ||\n\t\t!config.syncCoordinatorUrl ||\n\t\tconfig.syncCoordinatorGroups.length === 0\n\t) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 400,\n\t\t\terror: \"coordinator_not_configured\",\n\t\t\tdetail: \"Coordinator must be configured before accepting discovered peers.\",\n\t\t};\n\t}\n\tconst discovered = await lookupCoordinatorPeers(store, config);\n\tconst match = discovered.find(\n\t\t(peer) =>\n\t\t\tString(peer.device_id ?? \"\").trim() === input.peerDeviceId &&\n\t\t\tString(peer.fingerprint ?? \"\").trim() === input.fingerprint,\n\t);\n\tif (!match) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 404,\n\t\t\terror: \"discovered_peer_not_found\",\n\t\t\tdetail: \"That discovered device is no longer available. Refresh sync status and try again.\",\n\t\t};\n\t}\n\tconst nextFingerprint = String(match.fingerprint ?? \"\").trim();\n\tconst nextPublicKey = String(match.public_key ?? \"\").trim();\n\tconst nextName = String(match.display_name ?? \"\").trim() || null;\n\tconst nextAddresses = Array.isArray(match.addresses)\n\t\t? match.addresses.filter((value): value is string => typeof value === \"string\")\n\t\t: [];\n\tif (!nextPublicKey) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"discovered_peer_missing_public_key\",\n\t\t\tdetail:\n\t\t\t\t\"This discovered device is missing its coordinator public key. Refresh sync status and try again.\",\n\t\t};\n\t}\n\n\tconst groupIds = Array.isArray(match.groups)\n\t\t? match.groups.map((value) => String(value ?? \"\").trim()).filter(Boolean)\n\t\t: [];\n\tif (groupIds.length !== 1) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"ambiguous_coordinator_group\",\n\t\t\tdetail:\n\t\t\t\tgroupIds.length > 1\n\t\t\t\t\t? \"This device is visible through multiple coordinator groups. Review the team setup before approving it here.\"\n\t\t\t\t\t: \"This device is missing coordinator group context. Refresh sync status and try again.\",\n\t\t};\n\t}\n\tconst groupId = groupIds[0] as string;\n\tconst d = drizzle(store.db, { schema });\n\tconst existing = d\n\t\t.select({\n\t\t\tpeer_device_id: schema.syncPeers.peer_device_id,\n\t\t\tpinned_fingerprint: schema.syncPeers.pinned_fingerprint,\n\t\t\tpublic_key: schema.syncPeers.public_key,\n\t\t\taddresses_json: schema.syncPeers.addresses_json,\n\t\t})\n\t\t.from(schema.syncPeers)\n\t\t.where(eq(schema.syncPeers.peer_device_id, input.peerDeviceId))\n\t\t.get();\n\tconst existingFingerprint = String(existing?.pinned_fingerprint ?? \"\").trim();\n\tif (existing && existingFingerprint && existingFingerprint !== nextFingerprint) {\n\t\treturn {\n\t\t\tok: false as const,\n\t\t\tstatus: 409,\n\t\t\terror: \"peer_conflict\",\n\t\t\tdetail:\n\t\t\t\t\"An existing peer with this device id is pinned to a different fingerprint. Remove or repair the old peer before accepting this discovered device.\",\n\t\t};\n\t}\n\tconst existingAddresses = (() => {\n\t\ttry {\n\t\t\tconst raw = JSON.parse(String(existing?.addresses_json ?? \"[]\"));\n\t\t\treturn Array.isArray(raw)\n\t\t\t\t? raw.filter((value): value is string => typeof value === \"string\")\n\t\t\t\t: [];\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t})();\n\tconst addressesJson = JSON.stringify(mergeAddresses(existingAddresses, nextAddresses));\n\tawait createCoordinatorReciprocalApproval(store, config, {\n\t\tgroupId,\n\t\trequestedDeviceId: input.peerDeviceId,\n\t});\n\tconst now = new Date().toISOString();\n\tconst result = store.db.transaction(() => {\n\t\tif (!existing) {\n\t\t\td.insert(schema.syncPeers)\n\t\t\t\t.values({\n\t\t\t\t\tpeer_device_id: input.peerDeviceId,\n\t\t\t\t\tname: nextName,\n\t\t\t\t\tpinned_fingerprint: nextFingerprint || null,\n\t\t\t\t\tpublic_key: nextPublicKey,\n\t\t\t\t\taddresses_json: addressesJson,\n\t\t\t\t\tcreated_at: now,\n\t\t\t\t\tlast_seen_at: now,\n\t\t\t\t})\n\t\t\t\t.run();\n\t\t\treturn {\n\t\t\t\tok: true as const,\n\t\t\t\tpeer_device_id: input.peerDeviceId,\n\t\t\t\tcreated: true,\n\t\t\t\tupdated: false,\n\t\t\t\tname: nextName,\n\t\t\t};\n\t\t}\n\t\td.update(schema.syncPeers)\n\t\t\t.set({\n\t\t\t\tname: nextName,\n\t\t\t\tpinned_fingerprint: nextFingerprint || existing.pinned_fingerprint || null,\n\t\t\t\tpublic_key: nextPublicKey || existing.public_key || null,\n\t\t\t\taddresses_json: addressesJson,\n\t\t\t\tlast_seen_at: now,\n\t\t\t})\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, input.peerDeviceId))\n\t\t\t.run();\n\t\treturn {\n\t\t\tok: true as const,\n\t\t\tpeer_device_id: input.peerDeviceId,\n\t\t\tcreated: false,\n\t\t\tupdated: true,\n\t\t\tname: nextName,\n\t\t};\n\t})();\n\treturn result;\n}\n\nfunction filterOpsForPeer(\n\tstore: MemoryStore,\n\tpeerDeviceId: string,\n\tops: ReplicationOp[],\n): { allowed: ReplicationOp[]; skipped: number } {\n\tconst filters = readPeerProjectFilters(store, peerDeviceId);\n\tconst allowPrivate = peerClaimedLocalActor(store, peerDeviceId);\n\tconst allowed: ReplicationOp[] = [];\n\tlet skipped = 0;\n\tfor (const op of ops) {\n\t\tif (op.entity_type !== \"memory_item\") {\n\t\t\tallowed.push(op);\n\t\t\tcontinue;\n\t\t}\n\t\tconst payload = parseOpPayload(op);\n\t\tif (!allowPrivate && !syncVisibilityAllowed(payload)) {\n\t\t\tskipped++;\n\t\t\tcontinue;\n\t\t}\n\t\tconst project = payload && typeof payload.project === \"string\" ? payload.project : null;\n\t\tif (!syncProjectAllowedByFilters(project, filters)) {\n\t\t\tskipped++;\n\t\t\tcontinue;\n\t\t}\n\t\tallowed.push(op);\n\t}\n\treturn { allowed, skipped };\n}\n\n// ---------------------------------------------------------------------------\n// Peer row mapping — deduplicated helper (fix #4)\n// ---------------------------------------------------------------------------\n\n/**\n * Map a raw sync_peers DB row to the API response shape.\n * When showDiag is false, sensitive fields (fingerprint, last_error, addresses)\n * are redacted.\n */\nfunction mapPeerRow(\n\tstore: MemoryStore,\n\trow: Record<string, unknown>,\n\tshowDiag: boolean,\n): Record<string, unknown> {\n\treturn {\n\t\tpeer_device_id: row.peer_device_id,\n\t\tname: row.name,\n\t\tfingerprint: showDiag ? row.pinned_fingerprint : null,\n\t\tpinned: Boolean(row.pinned_fingerprint),\n\t\taddresses: showDiag ? safeJsonList(row.addresses_json as string | null) : [],\n\t\tlast_seen_at: row.last_seen_at,\n\t\tlast_sync_at: row.last_sync_at,\n\t\tlast_error: showDiag ? row.last_error : null,\n\t\thas_error: Boolean(row.last_error),\n\t\tclaimed_local_actor: Boolean(row.claimed_local_actor),\n\t\tactor_id: row.actor_id ?? null,\n\t\tactor_display_name: row.actor_display_name ?? null,\n\t\tproject_scope: {\n\t\t\t...currentProjectScope(row, readPeerProjectFilters(store, String(row.peer_device_id ?? \"\"))),\n\t\t},\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Peer status helpers\n// ---------------------------------------------------------------------------\n\nfunction isRecentIso(value: unknown, windowS = SYNC_STALE_AFTER_SECONDS): boolean {\n\tconst raw = String(value ?? \"\").trim();\n\tif (!raw) return false;\n\tconst normalized = raw.replace(\"Z\", \"+00:00\");\n\tconst hasOffset = /(?:Z|[+-]\\d{2}:?\\d{2})$/i.test(raw);\n\tconst ts = new Date(hasOffset ? normalized : `${normalized}+00:00`);\n\tif (Number.isNaN(ts.getTime())) return false;\n\tconst ageS = (Date.now() - ts.getTime()) / 1000;\n\treturn ageS >= 0 && ageS <= windowS;\n}\n\nfunction peerStatus(peer: Record<string, unknown>): Record<string, unknown> {\n\tconst lastSyncAt = peer.last_sync_at;\n\tconst lastPingAt = peer.last_seen_at;\n\tconst hasError = Boolean(peer.has_error);\n\n\tconst syncFresh = isRecentIso(lastSyncAt);\n\tconst pingFresh = isRecentIso(lastPingAt);\n\n\tlet peerState: string;\n\tif (hasError && !(syncFresh || pingFresh)) peerState = \"offline\";\n\telse if (hasError) peerState = \"degraded\";\n\telse if (syncFresh || pingFresh) peerState = \"online\";\n\telse if (lastSyncAt || lastPingAt) peerState = \"stale\";\n\telse peerState = \"unknown\";\n\n\tconst syncStatus = hasError ? \"error\" : syncFresh ? \"ok\" : lastSyncAt ? \"stale\" : \"unknown\";\n\tconst pingStatus = pingFresh ? \"ok\" : lastPingAt ? \"stale\" : \"unknown\";\n\n\treturn {\n\t\tsync_status: syncStatus,\n\t\tping_status: pingStatus,\n\t\tpeer_state: peerState,\n\t\tfresh: syncFresh || pingFresh,\n\t\tlast_sync_at: lastSyncAt,\n\t\tlast_ping_at: lastPingAt,\n\t};\n}\n\nfunction attemptStatus(attempt: Record<string, unknown>): string {\n\tif (attempt.ok) return \"ok\";\n\tif (attempt.error) return \"error\";\n\treturn \"unknown\";\n}\n\nfunction readViewerBinding(dbPath: string): { host: string; port: number } | null {\n\ttry {\n\t\tconst raw = readFileSync(join(dirname(dbPath), \"viewer.pid\"), \"utf8\");\n\t\tconst parsed = JSON.parse(raw) as Partial<{ host: string; port: number }>;\n\t\tif (typeof parsed.host === \"string\" && typeof parsed.port === \"number\") {\n\t\t\treturn { host: parsed.host, port: parsed.port };\n\t\t}\n\t} catch {\n\t\t// ignore missing/malformed pidfile\n\t}\n\treturn null;\n}\n\nasync function portOpen(host: string, port: number): Promise<boolean> {\n\treturn new Promise((resolve) => {\n\t\tconst socket = net.createConnection({ host, port });\n\t\tconst done = (ok: boolean) => {\n\t\t\tsocket.removeAllListeners();\n\t\t\tsocket.destroy();\n\t\t\tresolve(ok);\n\t\t};\n\t\tsocket.setTimeout(300);\n\t\tsocket.once(\"connect\", () => done(true));\n\t\tsocket.once(\"timeout\", () => done(false));\n\t\tsocket.once(\"error\", () => done(false));\n\t});\n}\n\nconst PEERS_QUERY = `\n\tSELECT p.peer_device_id, p.name, p.pinned_fingerprint, p.addresses_json,\n\t p.last_seen_at, p.last_sync_at, p.last_error,\n\t p.projects_include_json, p.projects_exclude_json, p.claimed_local_actor,\n\t p.actor_id, a.display_name AS actor_display_name\n\tFROM sync_peers AS p\n\tLEFT JOIN actors AS a ON a.actor_id = p.actor_id\n\tORDER BY name, peer_device_id\n`;\n\n// ---------------------------------------------------------------------------\n// Route factory\n// ---------------------------------------------------------------------------\n\n/**\n * Peer-to-peer sync protocol routes (/v1/*).\n *\n * These are mounted on the sync listener (0.0.0.0:7337) and are\n * network-accessible. All requests are auth-gated via signature\n * verification so unauthenticated callers are rejected.\n */\nexport function syncProtocolRoutes(getStore: StoreFactory, opts: SyncProtocolRouteOptions = {}) {\n\tconst app = new Hono();\n\tconst routeRateLimit = opts.routeRateLimit ?? null;\n\n\tfunction rateLimitedResponse(c: Context, key: string, authenticated: boolean) {\n\t\tif (!routeRateLimit) return null;\n\t\tconst isRead = c.req.method === \"GET\" || c.req.method === \"HEAD\" || c.req.method === \"OPTIONS\";\n\t\tconst result = routeRateLimit.limiter.check(\n\t\t\t`${c.req.method}:${authenticated ? \"auth\" : \"anon\"}:${key}`,\n\t\t\tauthenticated\n\t\t\t\t? isRead\n\t\t\t\t\t? routeRateLimit.readLimit\n\t\t\t\t\t: routeRateLimit.mutationLimit\n\t\t\t\t: isRead\n\t\t\t\t\t? routeRateLimit.unauthenticatedReadLimit\n\t\t\t\t\t: routeRateLimit.unauthenticatedMutationLimit,\n\t\t);\n\t\tif (result.allowed) return null;\n\t\tc.header(\"Retry-After\", String(result.retryAfterS));\n\t\treturn c.json({ error: \"rate_limited\", retry_after_s: result.retryAfterS }, 429);\n\t}\n\n\t// GET /v1/status (peer sync protocol)\n\tapp.get(\"/v1/status\", (c) => {\n\t\tconst store = getStore();\n\t\treturn (async () => {\n\t\t\tlet auth = authorizeSyncRequest(store, c.req, Buffer.alloc(0));\n\t\t\tlet preauthChecked = false;\n\t\t\tlet bootstrapAttempted = false;\n\t\t\tif (!auth.ok) {\n\t\t\t\tconst bootstrapGrantId = (c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim();\n\t\t\t\tif (bootstrapGrantId) {\n\t\t\t\t\tpreauthChecked = true;\n\t\t\t\t\t// Use unauthenticated bucket with stable key — grant is not yet verified,\n\t\t\t\t\t// so caller-controlled headers must not influence rate-limit identity.\n\t\t\t\t\tconst bootstrapLimited = rateLimitedResponse(c, c.req.path, false);\n\t\t\t\t\tif (bootstrapLimited) return bootstrapLimited;\n\t\t\t\t} else {\n\t\t\t\t\tpreauthChecked = true;\n\t\t\t\t\tconst unauthLimited = rateLimitedResponse(c, c.req.path, false);\n\t\t\t\t\tif (unauthLimited) return unauthLimited;\n\t\t\t\t}\n\t\t\t\tauth = await authorizeBootstrapGrantRequest(store, c.req, Buffer.alloc(0));\n\t\t\t\tbootstrapAttempted = true;\n\t\t\t}\n\t\t\tif (!auth.ok) {\n\t\t\t\t// Specific reasons are logged server-side; wire responses use a generic\n\t\t\t\t// reason to prevent info-disclosure.\n\t\t\t\tif (bootstrapAttempted) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sync] bootstrap grant auth failed: reason=${auth.reason} grant=${(c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim()} path=${c.req.path}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst wireReason = bootstrapAttempted ? \"bootstrap_grant_invalid\" : auth.reason;\n\t\t\t\treturn (\n\t\t\t\t\t(preauthChecked ? null : rateLimitedResponse(c, c.req.path, false)) ??\n\t\t\t\t\tc.json(unauthorizedPayload(wireReason), 401)\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst limited = rateLimitedResponse(c, auth.deviceId, true);\n\t\t\tif (limited) return limited;\n\n\t\t\ttry {\n\t\t\t\tconst [deviceId, fingerprint] = ensureDeviceIdentity(store.db, {\n\t\t\t\t\tkeysDir: syncKeysDir(),\n\t\t\t\t});\n\t\t\t\tconst syncReset = getSyncResetState(store.db);\n\t\t\t\treturn c.json({\n\t\t\t\t\tdevice_id: deviceId,\n\t\t\t\t\tprotocol_version: SYNC_PROTOCOL_VERSION,\n\t\t\t\t\tfingerprint,\n\t\t\t\t\tsync_reset: syncReset,\n\t\t\t\t});\n\t\t\t} catch {\n\t\t\t\treturn c.json({ error: \"internal_error\" }, 500);\n\t\t\t}\n\t\t})();\n\t});\n\n\t// GET /v1/ops (peer sync protocol)\n\tapp.get(\"/v1/ops\", (c) => {\n\t\tconst store = getStore();\n\t\tconst auth = authorizeSyncRequest(store, c.req, Buffer.alloc(0));\n\t\tif (!auth.ok)\n\t\t\treturn (\n\t\t\t\trateLimitedResponse(c, c.req.path, false) ?? c.json(unauthorizedPayload(auth.reason), 401)\n\t\t\t);\n\t\tconst limited = rateLimitedResponse(c, auth.deviceId, true);\n\t\tif (limited) return limited;\n\t\tconst peerDeviceId = auth.deviceId;\n\n\t\ttry {\n\t\t\tconst since = c.req.query(\"since\") ?? null;\n\t\t\tconst rawLimit = Number.parseInt(c.req.query(\"limit\") ?? \"200\", 10);\n\t\t\tconst rawGeneration = c.req.query(\"generation\");\n\t\t\tconst generation =\n\t\t\t\trawGeneration != null && rawGeneration.trim().length > 0\n\t\t\t\t\t? Number.parseInt(rawGeneration, 10)\n\t\t\t\t\t: null;\n\t\t\tconst snapshotId = c.req.query(\"snapshot_id\") ?? null;\n\t\t\tconst baselineCursor = c.req.query(\"baseline_cursor\") ?? null;\n\t\t\tconst limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(rawLimit, 1000)) : 200;\n\t\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\tconst result = loadReplicationOpsForPeer(store.db, {\n\t\t\t\tsince,\n\t\t\t\tlimit,\n\t\t\t\tdeviceId: localDeviceId,\n\t\t\t\tgeneration: Number.isFinite(generation) ? generation : null,\n\t\t\t\tsnapshotId,\n\t\t\t\tbaselineCursor,\n\t\t\t});\n\t\t\tif (result.reset_required) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"reset_required\",\n\t\t\t\t\t\t...result.reset,\n\t\t\t\t\t},\n\t\t\t\t\t409,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst { ops, nextCursor, boundary } = result;\n\t\t\tconst filtered = filterOpsForPeer(store, peerDeviceId, ops);\n\t\t\treturn c.json({\n\t\t\t\treset_required: false,\n\t\t\t\tgeneration: boundary.generation,\n\t\t\t\tsnapshot_id: boundary.snapshot_id,\n\t\t\t\tbaseline_cursor: boundary.baseline_cursor,\n\t\t\t\tretained_floor_cursor: boundary.retained_floor_cursor,\n\t\t\t\tops: filtered.allowed,\n\t\t\t\tnext_cursor: nextCursor,\n\t\t\t\tskipped: filtered.skipped,\n\t\t\t});\n\t\t} catch {\n\t\t\treturn c.json({ error: \"internal_error\" }, 500);\n\t\t}\n\t});\n\n\t// GET /v1/snapshot (peer sync protocol — bootstrap snapshot pages)\n\tapp.get(\"/v1/snapshot\", (c) => {\n\t\tconst store = getStore();\n\t\treturn (async () => {\n\t\t\tlet auth = authorizeSyncRequest(store, c.req, Buffer.alloc(0));\n\t\t\tlet preauthChecked = false;\n\t\t\tlet bootstrapAttempted = false;\n\t\t\tif (!auth.ok) {\n\t\t\t\tconst bootstrapGrantId = (c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim();\n\t\t\t\tif (bootstrapGrantId) {\n\t\t\t\t\tpreauthChecked = true;\n\t\t\t\t\t// Use unauthenticated bucket with stable key — grant is not yet verified,\n\t\t\t\t\t// so caller-controlled headers must not influence rate-limit identity.\n\t\t\t\t\tconst bootstrapLimited = rateLimitedResponse(c, c.req.path, false);\n\t\t\t\t\tif (bootstrapLimited) return bootstrapLimited;\n\t\t\t\t} else {\n\t\t\t\t\tpreauthChecked = true;\n\t\t\t\t\tconst unauthLimited = rateLimitedResponse(c, c.req.path, false);\n\t\t\t\t\tif (unauthLimited) return unauthLimited;\n\t\t\t\t}\n\t\t\t\tauth = await authorizeBootstrapGrantRequest(store, c.req, Buffer.alloc(0));\n\t\t\t\tbootstrapAttempted = true;\n\t\t\t}\n\t\t\tif (!auth.ok) {\n\t\t\t\t// Specific reasons are logged server-side; wire responses use a generic\n\t\t\t\t// reason to prevent info-disclosure.\n\t\t\t\tif (bootstrapAttempted) {\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sync] bootstrap grant auth failed: reason=${auth.reason} grant=${(c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim()} path=${c.req.path}`,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tconst wireReason = bootstrapAttempted ? \"bootstrap_grant_invalid\" : auth.reason;\n\t\t\t\treturn (\n\t\t\t\t\t(preauthChecked ? null : rateLimitedResponse(c, c.req.path, false)) ??\n\t\t\t\t\tc.json(unauthorizedPayload(wireReason), 401)\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst limited = rateLimitedResponse(c, auth.deviceId, true);\n\t\t\tif (limited) return limited;\n\n\t\t\ttry {\n\t\t\t\tconst rawGeneration = c.req.query(\"generation\");\n\t\t\t\tconst generation =\n\t\t\t\t\trawGeneration != null && rawGeneration.trim().length > 0\n\t\t\t\t\t\t? Number.parseInt(rawGeneration, 10)\n\t\t\t\t\t\t: null;\n\t\t\t\tconst snapshotId = c.req.query(\"snapshot_id\") ?? null;\n\t\t\t\tconst baselineCursor = c.req.query(\"baseline_cursor\") ?? null;\n\t\t\t\tconst pageToken = c.req.query(\"page_token\") ?? null;\n\t\t\t\tconst rawLimit = Number.parseInt(c.req.query(\"limit\") ?? \"200\", 10);\n\t\t\t\t// Cap raised to 5000 to support elevated bootstrap page sizes (default 2000).\n\t\t\t\tconst limit = Number.isFinite(rawLimit) ? Math.max(1, Math.min(rawLimit, 5000)) : 200;\n\n\t\t\t\tif (generation == null || !Number.isFinite(generation)) {\n\t\t\t\t\treturn c.json({ error: \"missing_generation\" }, 400);\n\t\t\t\t}\n\t\t\t\tif (!snapshotId) {\n\t\t\t\t\treturn c.json({ error: \"missing_snapshot_id\" }, 400);\n\t\t\t\t}\n\n\t\t\t\tconst result = loadMemorySnapshotPageForPeer(store.db, {\n\t\t\t\t\tgeneration,\n\t\t\t\t\tsnapshotId,\n\t\t\t\t\tbaselineCursor,\n\t\t\t\t\tpageToken,\n\t\t\t\t\tlimit,\n\t\t\t\t\tpeerDeviceId: auth.deviceId,\n\t\t\t\t});\n\n\t\t\t\treturn c.json({\n\t\t\t\t\tgeneration: result.boundary.generation,\n\t\t\t\t\tsnapshot_id: result.boundary.snapshot_id,\n\t\t\t\t\tbaseline_cursor: result.boundary.baseline_cursor,\n\t\t\t\t\tretained_floor_cursor: result.boundary.retained_floor_cursor,\n\t\t\t\t\titems: result.items,\n\t\t\t\t\tnext_page_token: result.nextPageToken,\n\t\t\t\t\thas_more: result.hasMore,\n\t\t\t\t});\n\t\t\t} catch (err) {\n\t\t\t\tconst message = err instanceof Error ? err.message : \"\";\n\t\t\t\tif (message === \"generation_mismatch\" || message === \"boundary_mismatch\") {\n\t\t\t\t\treturn c.json({ error: message }, 409);\n\t\t\t\t}\n\t\t\t\treturn c.json({ error: \"internal_error\" }, 500);\n\t\t\t}\n\t\t})();\n\t});\n\n\t// POST /v1/ops (peer sync protocol)\n\tapp.post(\"/v1/ops\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst raw = await readBoundedRequestBytes(c.req.raw, MAX_SYNC_BODY_BYTES);\n\t\tif (raw == null) {\n\t\t\treturn c.json({ error: \"payload_too_large\" }, 413);\n\t\t}\n\n\t\tconst auth = authorizeSyncRequest(store, c.req, raw);\n\t\tif (!auth.ok)\n\t\t\treturn (\n\t\t\t\trateLimitedResponse(c, c.req.path, false) ?? c.json(unauthorizedPayload(auth.reason), 401)\n\t\t\t);\n\t\tconst limited = rateLimitedResponse(c, auth.deviceId, true);\n\t\tif (limited) return limited;\n\t\tconst peerDeviceId = auth.deviceId;\n\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tconst parsed = JSON.parse(raw.toString(\"utf-8\")) as unknown;\n\t\t\tif (!parsed || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n\t\t\t\treturn c.json({ error: \"invalid_json\" }, 400);\n\t\t\t}\n\t\t\tbody = parsed as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid_json\" }, 400);\n\t\t}\n\n\t\tif (!Array.isArray(body.ops)) {\n\t\t\treturn c.json({ error: \"invalid_ops\" }, 400);\n\t\t}\n\t\tif (body.ops.length > MAX_SYNC_OPS) {\n\t\t\treturn c.json({ error: \"too_many_ops\" }, 413);\n\t\t}\n\n\t\tconst normalizedOps = extractReplicationOps(body);\n\t\tfor (const op of normalizedOps) {\n\t\t\tif (op.device_id !== peerDeviceId || op.clock_device_id !== peerDeviceId) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"invalid_op_device\",\n\t\t\t\t\t\treason: \"device_id_mismatch\",\n\t\t\t\t\t\top_id: op.op_id,\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\n\t\tconst filteredInbound = filterOpsForPeer(store, peerDeviceId, normalizedOps);\n\t\tconst result = applyReplicationOps(store.db, filteredInbound.allowed, localDeviceId);\n\t\treturn c.json({\n\t\t\t...result,\n\t\t\tskipped: result.skipped + filteredInbound.skipped,\n\t\t});\n\t});\n\n\treturn app;\n}\n\n/**\n * Viewer-facing sync management routes (/api/sync/*).\n *\n * These are mounted on the viewer listener (127.0.0.1:38888) and\n * provide sync status, peer management, and coordinator UI for the\n * local viewer.\n */\nexport function syncRoutes(\n\tgetStore: StoreFactory,\n\tgetSyncRuntimeStatus?: () => SyncRuntimeStatus | null,\n) {\n\tconst app = new Hono();\n\n\t// GET /api/sync/status\n\tapp.get(\"/api/sync/status\", async (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst traceSync = <T>(label: string, fn: () => T): T => {\n\t\t\t\tif (process.env.CODEMEM_TRACE_SYNC_STATUS !== \"1\") return fn();\n\t\t\t\tconst startedAt = Date.now();\n\t\t\t\tconsole.warn(`[codemem sync-status] ${label} start`);\n\t\t\t\ttry {\n\t\t\t\t\treturn fn();\n\t\t\t\t} finally {\n\t\t\t\t\tconsole.warn(`[codemem sync-status] ${label} ${Date.now() - startedAt}ms`);\n\t\t\t\t}\n\t\t\t};\n\t\t\tconst showDiag = queryBool(c.req.query(\"includeDiagnostics\"));\n\t\t\tconst includeJoinRequests = queryBool(c.req.query(\"includeJoinRequests\"));\n\t\t\tconst project = c.req.query(\"project\") || null;\n\t\t\tconst config = traceSync(\"readCoordinatorSyncConfig\", () => readCoordinatorSyncConfig());\n\t\t\tconst syncReset = traceSync(\"getSyncResetState\", () => getSyncResetState(store.db));\n\n\t\t\tconst d = drizzle(store.db, { schema });\n\n\t\t\tconst deviceRow = traceSync(\"deviceRow\", () =>\n\t\t\t\td\n\t\t\t\t\t.select({\n\t\t\t\t\t\tdevice_id: schema.syncDevice.device_id,\n\t\t\t\t\t\tfingerprint: schema.syncDevice.fingerprint,\n\t\t\t\t\t})\n\t\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t\t.limit(1)\n\t\t\t\t\t.get(),\n\t\t\t);\n\n\t\t\tconst daemonState = traceSync(\"daemonState\", () =>\n\t\t\t\td.select().from(schema.syncDaemonState).where(eq(schema.syncDaemonState.id, 1)).get(),\n\t\t\t);\n\n\t\t\tconst peerCountRow = traceSync(\"peerCountRow\", () =>\n\t\t\t\td.select({ total: count() }).from(schema.syncPeers).get(),\n\t\t\t);\n\t\t\tlet retentionState:\n\t\t\t\t| {\n\t\t\t\t\t\tlast_run_at?: string | null;\n\t\t\t\t\t\tlast_duration_ms?: number | null;\n\t\t\t\t\t\tlast_deleted_ops?: number | null;\n\t\t\t\t\t\tlast_estimated_bytes_before?: number | null;\n\t\t\t\t\t\tlast_estimated_bytes_after?: number | null;\n\t\t\t\t\t\tretained_floor_cursor?: string | null;\n\t\t\t\t\t\tlast_error?: string | null;\n\t\t\t\t\t\tlast_error_at?: string | null;\n\t\t\t\t }\n\t\t\t\t| undefined;\n\t\t\ttry {\n\t\t\t\tretentionState = traceSync(\"retentionState\", () =>\n\t\t\t\t\td\n\t\t\t\t\t\t.select()\n\t\t\t\t\t\t.from(schema.syncRetentionState)\n\t\t\t\t\t\t.where(eq(schema.syncRetentionState.id, 1))\n\t\t\t\t\t\t.get(),\n\t\t\t\t);\n\t\t\t} catch {\n\t\t\t\tretentionState = undefined;\n\t\t\t}\n\n\t\t\tconst lastSyncRow = traceSync(\"lastSyncRow\", () =>\n\t\t\t\td\n\t\t\t\t\t.select({ last_sync_at: max(schema.syncPeers.last_sync_at) })\n\t\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t\t.get(),\n\t\t\t);\n\t\t\tconst semanticIndex = traceSync(\"semanticIndex\", () =>\n\t\t\t\tredactSemanticIndexDiagnostics(\n\t\t\t\t\tgetSemanticIndexDiagnostics(store.db, { fastCounts: !showDiag }),\n\t\t\t\t\tshowDiag,\n\t\t\t\t),\n\t\t\t);\n\n\t\t\tconst lastError = daemonState?.last_error as string | null;\n\t\t\tconst lastErrorAt = daemonState?.last_error_at as string | null;\n\t\t\tconst lastOkAt = daemonState?.last_ok_at as string | null;\n\t\t\tconst viewerBinding = traceSync(\"readViewerBinding\", () => readViewerBinding(store.dbPath));\n\t\t\tconst daemonRunning = viewerBinding\n\t\t\t\t? await portOpen(viewerBinding.host, viewerBinding.port)\n\t\t\t\t: false;\n\t\t\tconst daemonDetail = viewerBinding\n\t\t\t\t? daemonRunning\n\t\t\t\t\t? `viewer pidfile at ${viewerBinding.host}:${viewerBinding.port}`\n\t\t\t\t\t: `pidfile present but ${viewerBinding.host}:${viewerBinding.port} is unreachable`\n\t\t\t\t: null;\n\n\t\t\tlet daemonStateValue = \"ok\";\n\t\t\tif (!config.syncEnabled) {\n\t\t\t\tdaemonStateValue = \"disabled\";\n\t\t\t} else if (lastError && (!lastOkAt || String(lastOkAt) < String(lastErrorAt ?? \"\"))) {\n\t\t\t\tdaemonStateValue = \"error\";\n\t\t\t} else if (!daemonRunning) {\n\t\t\t\tdaemonStateValue = \"stopped\";\n\t\t\t}\n\n\t\t\tconst statusPayload: Record<string, unknown> = {\n\t\t\t\tenabled: config.syncEnabled,\n\t\t\t\tinterval_s: config.syncIntervalS,\n\t\t\t\tretention: {\n\t\t\t\t\tenabled: config.syncRetentionEnabled,\n\t\t\t\t\tmax_age_days: config.syncRetentionMaxAgeDays,\n\t\t\t\t\tmax_size_mb: config.syncRetentionMaxSizeMb,\n\t\t\t\t\tretained_floor_cursor:\n\t\t\t\t\t\tsyncReset.retained_floor_cursor ??\n\t\t\t\t\t\t(retentionState?.retained_floor_cursor as string | null) ??\n\t\t\t\t\t\tnull,\n\t\t\t\t\tlast_run_at: (retentionState?.last_run_at as string | null) ?? null,\n\t\t\t\t\tlast_duration_ms:\n\t\t\t\t\t\ttypeof retentionState?.last_duration_ms === \"number\"\n\t\t\t\t\t\t\t? retentionState.last_duration_ms\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tlast_deleted_ops:\n\t\t\t\t\t\ttypeof retentionState?.last_deleted_ops === \"number\"\n\t\t\t\t\t\t\t? retentionState.last_deleted_ops\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tlast_estimated_bytes_before:\n\t\t\t\t\t\ttypeof retentionState?.last_estimated_bytes_before === \"number\"\n\t\t\t\t\t\t\t? retentionState.last_estimated_bytes_before\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tlast_estimated_bytes_after:\n\t\t\t\t\t\ttypeof retentionState?.last_estimated_bytes_after === \"number\"\n\t\t\t\t\t\t\t? retentionState.last_estimated_bytes_after\n\t\t\t\t\t\t\t: null,\n\t\t\t\t\tlast_error: (retentionState?.last_error as string | null) ?? null,\n\t\t\t\t\tlast_error_at: (retentionState?.last_error_at as string | null) ?? null,\n\t\t\t\t},\n\t\t\t\tsemantic_index: semanticIndex,\n\t\t\t\tpeer_count: Number(peerCountRow?.total ?? 0),\n\t\t\t\tlast_sync_at: lastSyncRow?.last_sync_at ?? null,\n\t\t\t\tdaemon_state: daemonStateValue,\n\t\t\t\tdaemon_running: daemonRunning,\n\t\t\t\tdaemon_detail: daemonDetail,\n\t\t\t\tproject_filter_active:\n\t\t\t\t\tconfig.syncProjectsInclude.length > 0 || config.syncProjectsExclude.length > 0,\n\t\t\t\tproject_filter: {\n\t\t\t\t\tinclude: config.syncProjectsInclude,\n\t\t\t\t\texclude: config.syncProjectsExclude,\n\t\t\t\t},\n\t\t\t\tredacted: !showDiag,\n\t\t\t};\n\n\t\t\tif (showDiag) {\n\t\t\t\tstatusPayload.device_id = deviceRow?.device_id ?? null;\n\t\t\t\tstatusPayload.fingerprint = deviceRow?.fingerprint ?? null;\n\t\t\t\tstatusPayload.bind = `${config.syncHost}:${config.syncPort}`;\n\t\t\t\tstatusPayload.daemon_last_error = lastError;\n\t\t\t\tstatusPayload.daemon_last_error_at = lastErrorAt;\n\t\t\t\tstatusPayload.daemon_last_ok_at = lastOkAt;\n\t\t\t}\n\n\t\t\tconst runtimeStatus = getSyncRuntimeStatus?.() ?? null;\n\t\t\tif (runtimeStatus?.phase && runtimeStatus.phase !== \"running\") {\n\t\t\t\tdaemonStateValue = runtimeStatus.phase;\n\t\t\t\tstatusPayload.daemon_state = daemonStateValue;\n\t\t\t\tstatusPayload.daemon_running = runtimeStatus.phase === \"starting\" || daemonRunning;\n\t\t\t\tstatusPayload.daemon_detail = runtimeStatus.detail ?? daemonDetail;\n\t\t\t}\n\n\t\t\t// Build peers list using deduplicated mapPeerRow\n\t\t\tconst peerRows = traceSync(\n\t\t\t\t\"peerRows\",\n\t\t\t\t() => store.db.prepare(PEERS_QUERY).all() as Record<string, unknown>[],\n\t\t\t);\n\t\t\tconst peersItems = peerRows.map((row) => {\n\t\t\t\tconst peer = mapPeerRow(store, row, showDiag);\n\t\t\t\tpeer.status = peerStatus(peer);\n\t\t\t\treturn peer;\n\t\t\t});\n\n\t\t\tconst peersMap: Record<string, unknown> = {};\n\t\t\tfor (const peer of peersItems) {\n\t\t\t\tpeersMap[String(peer.peer_device_id)] = peer.status;\n\t\t\t}\n\n\t\t\t// Attempts\n\t\t\tconst attemptRows = traceSync(\"attemptRows\", () =>\n\t\t\t\td\n\t\t\t\t\t.select({\n\t\t\t\t\t\tpeer_device_id: schema.syncAttempts.peer_device_id,\n\t\t\t\t\t\tok: schema.syncAttempts.ok,\n\t\t\t\t\t\terror: schema.syncAttempts.error,\n\t\t\t\t\t\tstarted_at: schema.syncAttempts.started_at,\n\t\t\t\t\t\tfinished_at: schema.syncAttempts.finished_at,\n\t\t\t\t\t\tops_in: schema.syncAttempts.ops_in,\n\t\t\t\t\t\tops_out: schema.syncAttempts.ops_out,\n\t\t\t\t\t})\n\t\t\t\t\t.from(schema.syncAttempts)\n\t\t\t\t\t.orderBy(desc(schema.syncAttempts.finished_at))\n\t\t\t\t\t.limit(25)\n\t\t\t\t\t.all(),\n\t\t\t);\n\t\t\tconst peerAddressMap = new Map<string, string[]>();\n\t\t\tconst peerAddressRows = traceSync(\n\t\t\t\t\"peerAddressRows\",\n\t\t\t\t() =>\n\t\t\t\t\tstore.db.prepare(\"SELECT peer_device_id, addresses_json FROM sync_peers\").all() as Array<{\n\t\t\t\t\t\tpeer_device_id: string | null;\n\t\t\t\t\t\taddresses_json: string | null;\n\t\t\t\t\t}>,\n\t\t\t);\n\t\t\tpeerAddressRows.forEach((peerRow) => {\n\t\t\t\tconst addrs = safeJsonList(peerRow.addresses_json as string | null);\n\t\t\t\tif (addrs.length) peerAddressMap.set(String(peerRow.peer_device_id ?? \"\"), addrs);\n\t\t\t});\n\t\t\tconst attemptsItems = attemptRows.map((row) => {\n\t\t\t\tconst addrs = showDiag ? peerAddressMap.get(String(row.peer_device_id ?? \"\")) : undefined;\n\t\t\t\treturn {\n\t\t\t\t\t...row,\n\t\t\t\t\tstatus: attemptStatus(row),\n\t\t\t\t\taddress: addrs?.length ? addrs[0] : null,\n\t\t\t\t};\n\t\t\t});\n\t\t\tconst latestAttemptError = String(attemptsItems[0]?.error || \"\").trim();\n\n\t\t\tconst statusBlock: Record<string, unknown> = {\n\t\t\t\t...statusPayload,\n\t\t\t\tbackground_maintenance: summarizeMaintenanceJobs(listMaintenanceJobs(store.db), showDiag),\n\t\t\t\tpeers: peersMap,\n\t\t\t\tpending: 0,\n\t\t\t\tsync: {},\n\t\t\t\tping: {},\n\t\t\t};\n\t\t\tconst legacyDevices = traceSync(\"legacyDevices\", () => store.claimableLegacyDeviceIds());\n\t\t\tconst sharingReview = traceSync(\"sharingReview\", () => store.sharingReviewSummary(project));\n\t\t\tconst coordinatorSnapshot = await coordinatorStatusSnapshot(store, config);\n\t\t\tconst coordinator = traceSync(\"coordinator\", () =>\n\t\t\t\tredactCoordinatorStatus(coordinatorSnapshot, showDiag),\n\t\t\t);\n\t\t\tlet joinRequests: Record<string, unknown>[] = [];\n\t\t\tif (includeJoinRequests && showDiag && config.syncCoordinatorAdminSecret) {\n\t\t\t\ttry {\n\t\t\t\t\tjoinRequests = await listCoordinatorJoinRequests(config);\n\t\t\t\t} catch {\n\t\t\t\t\tjoinRequests = [];\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (daemonStateValue === \"ok\" && latestAttemptError.startsWith(\"needs_attention:\")) {\n\t\t\t\tdaemonStateValue = \"needs_attention\";\n\t\t\t\tstatusPayload.daemon_state = daemonStateValue;\n\t\t\t\tstatusPayload.daemon_detail = latestAttemptError.replace(/^needs_attention:/, \"\");\n\t\t\t\tstatusBlock.daemon_state = daemonStateValue;\n\t\t\t\tstatusBlock.daemon_detail = latestAttemptError.replace(/^needs_attention:/, \"\");\n\t\t\t}\n\n\t\t\tif (daemonStateValue === \"ok\") {\n\t\t\t\tconst peerStates = new Set(\n\t\t\t\t\tpeersItems.map((peer) =>\n\t\t\t\t\t\tString((peer.status as Record<string, unknown> | undefined)?.peer_state ?? \"\"),\n\t\t\t\t\t),\n\t\t\t\t);\n\t\t\t\tconst latestFailedRecently = Boolean(\n\t\t\t\t\tattemptsItems[0] &&\n\t\t\t\t\t\tattemptsItems[0].status === \"error\" &&\n\t\t\t\t\t\tisRecentIso(attemptsItems[0].finished_at),\n\t\t\t\t);\n\t\t\t\tconst allOffline =\n\t\t\t\t\tpeersItems.length > 0 &&\n\t\t\t\t\tpeersItems.every(\n\t\t\t\t\t\t(peer) =>\n\t\t\t\t\t\t\tString((peer.status as Record<string, unknown>)?.peer_state ?? \"\") === \"offline\",\n\t\t\t\t\t);\n\t\t\t\tif (latestFailedRecently) {\n\t\t\t\t\tconst hasLivePeer = peerStates.has(\"online\") || peerStates.has(\"degraded\");\n\t\t\t\t\tif (hasLivePeer) daemonStateValue = \"degraded\";\n\t\t\t\t\telse if (allOffline) daemonStateValue = \"offline-peers\";\n\t\t\t\t\telse if (peersItems.length > 0) daemonStateValue = \"stale\";\n\t\t\t\t} else if (peerStates.has(\"degraded\")) {\n\t\t\t\t\tdaemonStateValue = \"degraded\";\n\t\t\t\t} else if (allOffline) {\n\t\t\t\t\tdaemonStateValue = \"offline-peers\";\n\t\t\t\t} else if (peersItems.length > 0 && !peerStates.has(\"online\")) {\n\t\t\t\t\tdaemonStateValue = \"stale\";\n\t\t\t\t}\n\t\t\t\tstatusPayload.daemon_state = daemonStateValue;\n\t\t\t\tstatusBlock.daemon_state = daemonStateValue;\n\t\t\t}\n\n\t\t\tconst responsePayload: Record<string, unknown> = {\n\t\t\t\t...statusPayload,\n\t\t\t\tstatus: statusBlock,\n\t\t\t\tpeers: peersItems,\n\t\t\t\tattempts: attemptsItems.slice(0, 5),\n\t\t\t\tlegacy_devices: legacyDevices,\n\t\t\t\tsharing_review: sharingReview,\n\t\t\t\tcoordinator,\n\t\t\t};\n\t\t\tif (includeJoinRequests && showDiag) {\n\t\t\t\tresponsePayload.join_requests = joinRequests;\n\t\t\t}\n\t\t\treturn c.json(responsePayload);\n\t\t}\n\t});\n\n\t// GET /api/sync/peers\n\tapp.get(\"/api/sync/peers\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst showDiag = queryBool(c.req.query(\"includeDiagnostics\"));\n\t\t\tconst rows = store.db.prepare(PEERS_QUERY).all() as Record<string, unknown>[];\n\t\t\t// Use deduplicated mapPeerRow helper (fix #4)\n\t\t\tconst peers = rows.map((row) => mapPeerRow(store, row, showDiag));\n\t\t\treturn c.json({ items: peers, redacted: !showDiag });\n\t\t}\n\t});\n\n\t// GET /api/sync/actors\n\tapp.get(\"/api/sync/actors\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tensureLocalActorRecord(store);\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst includeMerged = queryBool(c.req.query(\"includeMerged\"));\n\t\t\tconst query = d.select().from(schema.actors);\n\t\t\tconst rows = includeMerged\n\t\t\t\t? query.orderBy(schema.actors.display_name).all()\n\t\t\t\t: query\n\t\t\t\t\t\t.where(and(ne(schema.actors.status, \"merged\"), ne(schema.actors.status, \"deactivated\")))\n\t\t\t\t\t\t.orderBy(schema.actors.display_name)\n\t\t\t\t\t\t.all();\n\t\t\treturn c.json({ items: rows });\n\t\t}\n\t});\n\n\t// GET /api/sync/attempts\n\tapp.get(\"/api/sync/attempts\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tlet limit = queryInt(c.req.query(\"limit\"), 25);\n\t\t\tif (limit <= 0) return c.json({ error: \"invalid_limit\" }, 400);\n\t\t\tlimit = Math.min(limit, 500);\n\t\t\tconst rows = d\n\t\t\t\t.select({\n\t\t\t\t\tpeer_device_id: schema.syncAttempts.peer_device_id,\n\t\t\t\t\tok: schema.syncAttempts.ok,\n\t\t\t\t\terror: schema.syncAttempts.error,\n\t\t\t\t\tstarted_at: schema.syncAttempts.started_at,\n\t\t\t\t\tfinished_at: schema.syncAttempts.finished_at,\n\t\t\t\t\tops_in: schema.syncAttempts.ops_in,\n\t\t\t\t\tops_out: schema.syncAttempts.ops_out,\n\t\t\t\t})\n\t\t\t\t.from(schema.syncAttempts)\n\t\t\t\t.orderBy(desc(schema.syncAttempts.finished_at))\n\t\t\t\t.limit(limit)\n\t\t\t\t.all();\n\t\t\treturn c.json({ items: rows });\n\t\t}\n\t});\n\n\t// GET /api/sync/pairing — uses ensureDeviceIdentity from core (fix #5 context)\n\tapp.get(\"/api/sync/pairing\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst showDiag = queryBool(c.req.query(\"includeDiagnostics\"));\n\t\t\tif (!showDiag) {\n\t\t\t\treturn c.json({\n\t\t\t\t\tredacted: true,\n\t\t\t\t\tpairing_filter_hint: PAIRING_FILTER_HINT,\n\t\t\t\t});\n\t\t\t}\n\t\t\tconst config = readCoordinatorSyncConfig();\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst deviceRow = d\n\t\t\t\t.select({\n\t\t\t\t\tdevice_id: schema.syncDevice.device_id,\n\t\t\t\t\tpublic_key: schema.syncDevice.public_key,\n\t\t\t\t\tfingerprint: schema.syncDevice.fingerprint,\n\t\t\t\t})\n\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t.limit(1)\n\t\t\t\t.get();\n\n\t\t\tlet deviceId: string | undefined;\n\t\t\tlet publicKey: string | undefined;\n\t\t\tlet fingerprint: string | undefined;\n\n\t\t\tif (deviceRow) {\n\t\t\t\tdeviceId = String(deviceRow.device_id);\n\t\t\t\tpublicKey = String(deviceRow.public_key);\n\t\t\t\tfingerprint = String(deviceRow.fingerprint);\n\t\t\t} else {\n\t\t\t\t// Fall back to ensureDeviceIdentity if no row exists\n\t\t\t\ttry {\n\t\t\t\t\tconst [id, fp] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\t\t\tdeviceId = id;\n\t\t\t\t\tfingerprint = fp;\n\t\t\t\t\tconst newRow = d\n\t\t\t\t\t\t.select({ public_key: schema.syncDevice.public_key })\n\t\t\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t\t\t.where(eq(schema.syncDevice.device_id, id))\n\t\t\t\t\t\t.get();\n\t\t\t\t\tpublicKey = newRow?.public_key ?? \"\";\n\t\t\t\t} catch {\n\t\t\t\t\treturn c.json({ error: \"device identity unavailable\" }, 500);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (!deviceId || !fingerprint) {\n\t\t\t\treturn c.json({ error: \"public key missing\" }, 500);\n\t\t\t}\n\n\t\t\treturn c.json({\n\t\t\t\tdevice_id: deviceId,\n\t\t\t\tfingerprint,\n\t\t\t\tpublic_key: publicKey ?? null,\n\t\t\t\tpairing_filter_hint: PAIRING_FILTER_HINT,\n\t\t\t\taddresses: pairingAdvertiseAddresses(config),\n\t\t\t});\n\t\t}\n\t});\n\n\t// ------------------------------------------------------------------\n\t// POST mutations\n\t// ------------------------------------------------------------------\n\n\t// POST /api/sync/peers/rename\n\tapp.post(\"/api/sync/peers/rename\", async (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst body = await c.req.json<Record<string, unknown>>();\n\t\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\t\tconst name = String(body.name ?? \"\").trim();\n\t\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\t\tif (!name) return c.json({ error: \"name required\" }, 400);\n\t\t\tconst exists = d\n\t\t\t\t.select({ peer_device_id: schema.syncPeers.peer_device_id })\n\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t\t.get();\n\t\t\tif (!exists) return c.json({ error: \"peer not found\" }, 404);\n\t\t\td.update(schema.syncPeers)\n\t\t\t\t.set({ name })\n\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t\t.run();\n\t\t\treturn c.json({ ok: true });\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/run\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown> = {};\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\tbody = {};\n\t\t}\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tif (!config.syncEnabled) {\n\t\t\treturn c.json({ error: \"sync_disabled\" }, 403);\n\t\t}\n\t\tconst address =\n\t\t\ttypeof body.address === \"string\" && body.address.trim() ? body.address.trim() : null;\n\t\tconst requestedPeerId =\n\t\t\ttypeof body.peer_device_id === \"string\" && body.peer_device_id.trim()\n\t\t\t\t? body.peer_device_id.trim()\n\t\t\t\t: null;\n\t\tlet peerIds: string[];\n\t\tif (address) {\n\t\t\tconst peerId = findPeerDeviceIdForAddress(store, address);\n\t\t\tif (!peerId) return c.json({ error: \"unknown peer address\" }, 404);\n\t\t\tpeerIds = [peerId];\n\t\t} else if (requestedPeerId) {\n\t\t\tconst requestedPeerRows = store.db\n\t\t\t\t.prepare(\"SELECT peer_device_id FROM sync_peers WHERE peer_device_id = ?\")\n\t\t\t\t.all(requestedPeerId) as Array<{ peer_device_id: string | null }>;\n\t\t\tpeerIds = requestedPeerRows\n\t\t\t\t.map((row) => String(row.peer_device_id ?? \"\").trim())\n\t\t\t\t.filter(Boolean);\n\t\t} else {\n\t\t\tconst allPeerRows = store.db.prepare(\"SELECT peer_device_id FROM sync_peers\").all() as Array<{\n\t\t\t\tpeer_device_id: string | null;\n\t\t\t}>;\n\t\t\tpeerIds = allPeerRows.map((row) => String(row.peer_device_id ?? \"\").trim()).filter(Boolean);\n\t\t}\n\t\tconst items = [] as Array<Record<string, unknown>>;\n\t\tfor (const peerId of peerIds) {\n\t\t\tconst result = await runSyncPass(store.db, peerId);\n\t\t\titems.push({ peer_device_id: peerId, ...result });\n\t\t}\n\t\treturn c.json({ items });\n\t});\n\n\tapp.post(\"/api/sync/peers/scope\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\tconst include = Array.isArray(body.include)\n\t\t\t? body.include\n\t\t\t\t\t.filter((value): value is string => typeof value === \"string\")\n\t\t\t\t\t.map((value) => value.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t: null;\n\t\tconst exclude = Array.isArray(body.exclude)\n\t\t\t? body.exclude\n\t\t\t\t\t.filter((value): value is string => typeof value === \"string\")\n\t\t\t\t\t.map((value) => value.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t: null;\n\t\tconst inheritGlobal = Boolean(body.inherit_global);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst exists = d\n\t\t\t.select({ peer_device_id: schema.syncPeers.peer_device_id })\n\t\t\t.from(schema.syncPeers)\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.get();\n\t\tif (!exists) return c.json({ error: \"peer not found\" }, 404);\n\t\td.update(schema.syncPeers)\n\t\t\t.set({\n\t\t\t\tprojects_include_json: inheritGlobal ? null : JSON.stringify(include ?? []),\n\t\t\t\tprojects_exclude_json: inheritGlobal ? null : JSON.stringify(exclude ?? []),\n\t\t\t})\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.run();\n\t\tconst row = d\n\t\t\t.select({\n\t\t\t\tprojects_include_json: schema.syncPeers.projects_include_json,\n\t\t\t\tprojects_exclude_json: schema.syncPeers.projects_exclude_json,\n\t\t\t})\n\t\t\t.from(schema.syncPeers)\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.get() as Record<string, unknown> | undefined;\n\t\tif (!row) return c.json({ error: \"peer not found\" }, 404);\n\t\treturn c.json({\n\t\t\tok: true,\n\t\t\tproject_scope: currentProjectScope(row, readPeerProjectFilters(store, peerDeviceId)),\n\t\t});\n\t});\n\n\tapp.post(\"/api/sync/peers/identity\", async (c) => {\n\t\tconst store = getStore();\n\t\tensureLocalActorRecord(store);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\tconst requestedActorId =\n\t\t\tbody.actor_id == null ? undefined : String(body.actor_id ?? \"\").trim() || null;\n\t\tconst claimedLocalActor =\n\t\t\ttypeof body.claimed_local_actor === \"boolean\" ? body.claimed_local_actor : undefined;\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst peer = d\n\t\t\t.select({\n\t\t\t\tpeer_device_id: schema.syncPeers.peer_device_id,\n\t\t\t\tactor_id: schema.syncPeers.actor_id,\n\t\t\t\tclaimed_local_actor: schema.syncPeers.claimed_local_actor,\n\t\t\t})\n\t\t\t.from(schema.syncPeers)\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.get();\n\t\tif (!peer) return c.json({ error: \"peer not found\" }, 404);\n\n\t\tlet nextActorId = peer.actor_id ?? null;\n\t\tlet nextClaimedLocalActor = Boolean(peer.claimed_local_actor);\n\t\tif (requestedActorId !== undefined) {\n\t\t\tnextActorId = requestedActorId;\n\t\t\tif (requestedActorId) {\n\t\t\t\tconst actor = d\n\t\t\t\t\t.select({\n\t\t\t\t\t\tactor_id: schema.actors.actor_id,\n\t\t\t\t\t\tis_local: schema.actors.is_local,\n\t\t\t\t\t\tstatus: schema.actors.status,\n\t\t\t\t\t})\n\t\t\t\t\t.from(schema.actors)\n\t\t\t\t\t.where(eq(schema.actors.actor_id, requestedActorId))\n\t\t\t\t\t.get();\n\t\t\t\tif (!actor) return c.json({ error: \"actor not found\" }, 404);\n\t\t\t\tif (actor.status !== \"active\") return c.json({ error: \"actor not active\" }, 409);\n\t\t\t\tnextClaimedLocalActor = claimedLocalActor ?? Boolean(actor.is_local);\n\t\t\t} else {\n\t\t\t\tnextClaimedLocalActor = claimedLocalActor ?? false;\n\t\t\t}\n\t\t} else if (claimedLocalActor !== undefined) {\n\t\t\tnextClaimedLocalActor = claimedLocalActor;\n\t\t\tif (claimedLocalActor) {\n\t\t\t\tnextActorId = store.actorId;\n\t\t\t} else if (nextActorId === store.actorId) {\n\t\t\t\tnextActorId = null;\n\t\t\t}\n\t\t}\n\n\t\td.update(schema.syncPeers)\n\t\t\t.set({\n\t\t\t\tactor_id: nextActorId,\n\t\t\t\tclaimed_local_actor: nextClaimedLocalActor ? 1 : 0,\n\t\t\t})\n\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t.run();\n\t\treturn c.json({ ok: true, actor_id: nextActorId, claimed_local_actor: nextClaimedLocalActor });\n\t});\n\n\tapp.post(\"/api/sync/actors\", async (c) => {\n\t\tconst store = getStore();\n\t\tensureLocalActorRecord(store);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst displayName = String(body.display_name ?? \"\").trim();\n\t\tif (!displayName) return c.json({ error: \"display_name required\" }, 400);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst now = new Date().toISOString();\n\t\tconst actor = {\n\t\t\tactor_id: randomUUID(),\n\t\t\tdisplay_name: displayName,\n\t\t\tis_local: 0,\n\t\t\tstatus: \"active\",\n\t\t\tmerged_into_actor_id: null,\n\t\t\tcreated_at: now,\n\t\t\tupdated_at: now,\n\t\t};\n\t\td.insert(schema.actors).values(actor).run();\n\t\treturn c.json(actor);\n\t});\n\n\tapp.post(\"/api/sync/actors/rename\", async (c) => {\n\t\tconst store = getStore();\n\t\tensureLocalActorRecord(store);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst actorId = String(body.actor_id ?? \"\").trim();\n\t\tconst displayName = String(body.display_name ?? \"\").trim();\n\t\tif (!actorId) return c.json({ error: \"actor_id required\" }, 400);\n\t\tif (!displayName) return c.json({ error: \"display_name required\" }, 400);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst actor = d.select().from(schema.actors).where(eq(schema.actors.actor_id, actorId)).get();\n\t\tif (!actor) return c.json({ error: \"actor not found\" }, 404);\n\t\tconst updatedAt = new Date().toISOString();\n\t\td.update(schema.actors)\n\t\t\t.set({ display_name: displayName, updated_at: updatedAt })\n\t\t\t.where(eq(schema.actors.actor_id, actorId))\n\t\t\t.run();\n\t\treturn c.json({ ...actor, display_name: displayName, updated_at: updatedAt });\n\t});\n\n\tapp.post(\"/api/sync/actors/merge\", async (c) => {\n\t\tconst store = getStore();\n\t\tensureLocalActorRecord(store);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst primaryActorId = String(body.primary_actor_id ?? \"\").trim();\n\t\tconst secondaryActorId = String(body.secondary_actor_id ?? \"\").trim();\n\t\tif (!primaryActorId) return c.json({ error: \"primary_actor_id required\" }, 400);\n\t\tif (!secondaryActorId) return c.json({ error: \"secondary_actor_id required\" }, 400);\n\t\tif (primaryActorId === secondaryActorId) return c.json({ error: \"actor ids must differ\" }, 400);\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst primary = d\n\t\t\t.select()\n\t\t\t.from(schema.actors)\n\t\t\t.where(eq(schema.actors.actor_id, primaryActorId))\n\t\t\t.get();\n\t\tconst secondary = d\n\t\t\t.select()\n\t\t\t.from(schema.actors)\n\t\t\t.where(eq(schema.actors.actor_id, secondaryActorId))\n\t\t\t.get();\n\t\tif (!primary || !secondary) return c.json({ error: \"actor not found\" }, 404);\n\t\tif (primary.status !== \"active\") return c.json({ error: \"primary actor not active\" }, 409);\n\t\tif (secondary.status !== \"active\") return c.json({ error: \"secondary actor not active\" }, 409);\n\t\tif (secondary.is_local && secondary.actor_id === store.actorId) {\n\t\t\treturn c.json({ error: \"cannot merge this device's own local actor\" }, 409);\n\t\t}\n\t\tconst now = new Date().toISOString();\n\t\tconst mergedCount = store.db.transaction(() => {\n\t\t\tconst peerUpdate = d\n\t\t\t\t.update(schema.syncPeers)\n\t\t\t\t.set({ actor_id: primaryActorId })\n\t\t\t\t.where(eq(schema.syncPeers.actor_id, secondaryActorId))\n\t\t\t\t.run();\n\t\t\tif (primary.is_local) {\n\t\t\t\td.update(schema.syncPeers)\n\t\t\t\t\t.set({ claimed_local_actor: 1 })\n\t\t\t\t\t.where(eq(schema.syncPeers.actor_id, primaryActorId))\n\t\t\t\t\t.run();\n\t\t\t}\n\t\t\td.update(schema.actors)\n\t\t\t\t.set({ status: \"merged\", merged_into_actor_id: primaryActorId, updated_at: now })\n\t\t\t\t.where(eq(schema.actors.actor_id, secondaryActorId))\n\t\t\t\t.run();\n\t\t\treturn Number(peerUpdate.changes ?? 0);\n\t\t})();\n\t\treturn c.json({ merged_count: mergedCount });\n\t});\n\n\tapp.post(\"/api/sync/actors/deactivate\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst actorId = String(body.actor_id ?? \"\").trim();\n\t\tif (!actorId) return c.json({ error: \"actor_id required\" }, 400);\n\t\tif (actorId === store.actorId) {\n\t\t\treturn c.json({ error: \"cannot deactivate this device's own local actor\" }, 409);\n\t\t}\n\t\tconst d = drizzle(store.db, { schema });\n\t\tconst actor = d.select().from(schema.actors).where(eq(schema.actors.actor_id, actorId)).get();\n\t\tif (!actor) return c.json({ error: \"actor not found\" }, 404);\n\t\tif (actor.status !== \"active\") return c.json({ error: \"actor not active\" }, 409);\n\t\tconst now = new Date().toISOString();\n\t\td.update(schema.actors)\n\t\t\t.set({ status: \"deactivated\", updated_at: now })\n\t\t\t.where(eq(schema.actors.actor_id, actorId))\n\t\t\t.run();\n\t\td.update(schema.syncPeers)\n\t\t\t.set({ actor_id: null })\n\t\t\t.where(eq(schema.syncPeers.actor_id, actorId))\n\t\t\t.run();\n\t\treturn c.json({ ok: true });\n\t});\n\n\tapp.post(\"/api/sync/legacy-devices/claim\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst originDeviceId = String(body.origin_device_id ?? \"\").trim();\n\t\tif (!originDeviceId) return c.json({ error: \"origin_device_id required\" }, 400);\n\t\tconst updated = claimLegacyDeviceAsSelf(store, originDeviceId);\n\t\tif (updated <= 0) return c.json({ error: \"legacy device not found\" }, 404);\n\t\treturn c.json({ ok: true, origin_device_id: originDeviceId, updated });\n\t});\n\n\tapp.post(\"/api/sync/peers/accept-discovered\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\tconst fingerprint = String(body.fingerprint ?? \"\").trim();\n\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\tif (!fingerprint) return c.json({ error: \"fingerprint required\" }, 400);\n\t\ttry {\n\t\t\tconst result = await acceptDiscoveredPeer(store, { peerDeviceId, fingerprint });\n\t\t\tif (!result.ok) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{ error: result.error, detail: result.detail },\n\t\t\t\t\t{ status: result.status as 400 | 404 | 409 },\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json({\n\t\t\t\tok: true,\n\t\t\t\tpeer_device_id: result.peer_device_id,\n\t\t\t\tcreated: result.created,\n\t\t\t\tupdated: result.updated,\n\t\t\t\tname: result.name,\n\t\t\t\tneeds_scope_review: true,\n\t\t\t});\n\t\t} catch (error) {\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: \"coordinator_lookup_failed\",\n\t\t\t\t\tdetail: error instanceof Error ? error.message : String(error),\n\t\t\t\t},\n\t\t\t\t{ status: 502 },\n\t\t\t);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/invites/create\", async (c) => {\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst groupId = String(body.group_id ?? \"\").trim();\n\t\tconst coordinatorUrl = body.coordinator_url == null ? null : String(body.coordinator_url ?? \"\");\n\t\tconst policy = String(body.policy ?? \"auto_admit\").trim();\n\t\tconst ttlHours = parseInviteTtlHours(body.ttl_hours);\n\t\tif (!groupId) return c.json({ error: \"group_id required\" }, 400);\n\t\tif (body.coordinator_url != null && typeof body.coordinator_url !== \"string\") {\n\t\t\treturn c.json({ error: \"coordinator_url must be string\" }, 400);\n\t\t}\n\t\tif (![\"auto_admit\", \"approval_required\"].includes(policy)) {\n\t\t\treturn c.json({ error: \"policy must be auto_admit or approval_required\" }, 400);\n\t\t}\n\t\tif (ttlHours == null) return c.json({ error: \"ttl_hours must be an integer >= 1\" }, 400);\n\t\ttry {\n\t\t\tconst config = readCoordinatorSyncConfig();\n\t\t\tconst result = await coordinatorCreateInviteAction({\n\t\t\t\tgroupId,\n\t\t\t\tcoordinatorUrl,\n\t\t\t\tpolicy,\n\t\t\t\tttlHours,\n\t\t\t\tcreatedBy: null,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error) }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/invites/import\", async (c) => {\n\t\tconst store = getStore();\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst inviteValue = String(body.invite ?? \"\").trim();\n\t\tif (!inviteValue) return c.json({ error: \"invite required\" }, 400);\n\t\ttry {\n\t\t\tconst result = await coordinatorImportInviteAction({ inviteValue, dbPath: store.dbPath });\n\t\t\treturn c.json(result);\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error) }, 400);\n\t\t}\n\t});\n\n\tapp.get(\"/api/coordinator/admin/status\", async (c) => {\n\t\tconst status = coordinatorAdminStatusPayload();\n\t\treturn c.json(status);\n\t});\n\n\tapp.get(\"/api/coordinator/admin/groups\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst includeArchived = queryBool(c.req.query(\"include_archived\"));\n\t\ttry {\n\t\t\tconst items = await coordinatorListGroupsAction({\n\t\t\t\tincludeArchived,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ items, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message, status }, 502);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\", status }, 400);\n\t\t}\n\t\tconst groupId = String(body.group_id ?? \"\").trim();\n\t\tconst displayName = String(body.display_name ?? \"\").trim() || null;\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst group = await coordinatorCreateGroupAction({\n\t\t\t\tgroupId,\n\t\t\t\tdisplayName,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ ok: true, group, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/rename\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\", status }, 400);\n\t\t}\n\t\tconst displayName = String(body.display_name ?? \"\").trim();\n\t\tif (!displayName) return c.json({ error: \"display_name required\", status }, 400);\n\t\ttry {\n\t\t\tconst group = await coordinatorRenameGroupAction({\n\t\t\t\tgroupId,\n\t\t\t\tdisplayName,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!group) return c.json({ error: \"group_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, group, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/archive\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst group = await coordinatorArchiveGroupAction({\n\t\t\t\tgroupId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!group) return c.json({ error: \"group_not_found_or_already_archived\", status }, 404);\n\t\t\treturn c.json({ ok: true, group, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/unarchive\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst group = await coordinatorUnarchiveGroupAction({\n\t\t\t\tgroupId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!group) return c.json({ error: \"group_not_found_or_not_archived\", status }, 404);\n\t\t\treturn c.json({ ok: true, group, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/invites\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\", status }, 400);\n\t\t}\n\t\tconst groupId = resolveCoordinatorAdminGroup(String(body.group_id ?? \"\").trim(), status);\n\t\tconst coordinatorUrl = body.coordinator_url == null ? null : String(body.coordinator_url ?? \"\");\n\t\tconst policy = String(body.policy ?? \"auto_admit\").trim();\n\t\tconst ttlHours = parseInviteTtlHours(body.ttl_hours);\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (body.coordinator_url != null && typeof body.coordinator_url !== \"string\") {\n\t\t\treturn c.json({ error: \"coordinator_url must be string\", status }, 400);\n\t\t}\n\t\tif (![\"auto_admit\", \"approval_required\"].includes(policy)) {\n\t\t\treturn c.json({ error: \"policy must be auto_admit or approval_required\", status }, 400);\n\t\t}\n\t\tif (ttlHours == null) {\n\t\t\treturn c.json({ error: \"ttl_hours must be an integer >= 1\", status }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst result = await coordinatorCreateInviteAction({\n\t\t\t\tgroupId,\n\t\t\t\tcoordinatorUrl,\n\t\t\t\tpolicy,\n\t\t\t\tttlHours,\n\t\t\t\tcreatedBy: null,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ ...result, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.get(\"/api/coordinator/admin/join-requests\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = resolveCoordinatorAdminGroup(c.req.query(\"group_id\"), status);\n\t\tif (!groupId) return c.json({ error: \"group_id_required\", status }, 400);\n\t\ttry {\n\t\t\tconst items = await coordinatorListJoinRequestsAction({\n\t\t\t\tgroupId,\n\t\t\t\tremoteUrl: status.coordinator_url,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ items, group_id: groupId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message, status }, 502);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/join-requests/:request_id/approve\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst requestId = String(c.req.param(\"request_id\") ?? \"\").trim();\n\t\tif (!requestId) return c.json({ error: \"request_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst result = await coordinatorReviewJoinRequestAction({\n\t\t\t\trequestId,\n\t\t\t\tapprove: true,\n\t\t\t\treviewedBy: null,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!result) return c.json({ error: \"join request not found\", status }, 404);\n\t\t\treturn c.json({ ok: true, request: result, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json(\n\t\t\t\t{ error: message, status },\n\t\t\t\tmessage.includes(\"request_not_found\") || message.includes(\"not found\") ? 404 : 400,\n\t\t\t);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/join-requests/:request_id/deny\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst requestId = String(c.req.param(\"request_id\") ?? \"\").trim();\n\t\tif (!requestId) return c.json({ error: \"request_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst result = await coordinatorReviewJoinRequestAction({\n\t\t\t\trequestId,\n\t\t\t\tapprove: false,\n\t\t\t\treviewedBy: null,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!result) return c.json({ error: \"join request not found\", status }, 404);\n\t\t\treturn c.json({ ok: true, request: result, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json(\n\t\t\t\t{ error: message, status },\n\t\t\t\tmessage.includes(\"request_not_found\") || message.includes(\"not found\") ? 404 : 400,\n\t\t\t);\n\t\t}\n\t});\n\n\tapp.get(\"/api/coordinator/admin/devices\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst groupId = resolveCoordinatorAdminGroup(c.req.query(\"group_id\"), status);\n\t\tif (!groupId) return c.json({ error: \"group_id_required\", status }, 400);\n\t\ttry {\n\t\t\tconst items = await coordinatorListDevicesAction({\n\t\t\t\tgroupId,\n\t\t\t\tincludeDisabled: queryBool(c.req.query(\"include_disabled\")),\n\t\t\t\tremoteUrl: status.coordinator_url,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ items, group_id: groupId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message, status }, 502);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/devices/:device_id/rename\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst deviceId = String(c.req.param(\"device_id\") ?? \"\").trim();\n\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\", status }, 400);\n\t\t}\n\t\tconst groupId = resolveCoordinatorAdminGroup(String(body.group_id ?? \"\").trim(), status);\n\t\tconst displayName = String(body.display_name ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (!displayName) return c.json({ error: \"display_name required\", status }, 400);\n\t\ttry {\n\t\t\tconst device = await coordinatorRenameDeviceAction({\n\t\t\t\tgroupId,\n\t\t\t\tdeviceId,\n\t\t\t\tdisplayName,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!device) return c.json({ error: \"device_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, device, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/devices/:device_id/disable\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst deviceId = String(c.req.param(\"device_id\") ?? \"\").trim();\n\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\tconst groupId = resolveCoordinatorAdminGroup(c.req.query(\"group_id\"), status);\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst ok = await coordinatorDisableDeviceAction({\n\t\t\t\tgroupId,\n\t\t\t\tdeviceId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!ok) return c.json({ error: \"device_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, device_id: deviceId, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/devices/:device_id/remove\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tif (status.readiness === \"not_configured\") {\n\t\t\treturn c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\t}\n\t\tif (!status.has_admin_secret) {\n\t\t\treturn c.json({ error: \"coordinator_admin_secret_missing\", status }, 400);\n\t\t}\n\t\tconst deviceId = String(c.req.param(\"device_id\") ?? \"\").trim();\n\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\tconst groupId = resolveCoordinatorAdminGroup(c.req.query(\"group_id\"), status);\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst ok = await coordinatorRemoveDeviceAction({\n\t\t\t\tgroupId,\n\t\t\t\tdeviceId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!ok) return c.json({ error: \"device_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, device_id: deviceId, status });\n\t\t} catch (error) {\n\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error), status }, 400);\n\t\t}\n\t});\n\n\tapp.get(\"/api/sync/bootstrap-grants\", async (c) => {\n\t\tconst groupId = String(c.req.query(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id_required\" }, 400);\n\t\tconst config = readCoordinatorSyncConfig();\n\t\ttry {\n\t\t\tconst items = await coordinatorListBootstrapGrantsAction({\n\t\t\t\tgroupId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\treturn c.json({ items });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message }, 500);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/bootstrap-grants/revoke\", async (c) => {\n\t\tlet body: Record<string, unknown>;\n\t\ttry {\n\t\t\tbody = await c.req.json<Record<string, unknown>>();\n\t\t} catch {\n\t\t\treturn c.json({ error: \"invalid json\" }, 400);\n\t\t}\n\t\tconst grantId = String(body.grant_id ?? \"\").trim();\n\t\tif (!grantId) return c.json({ error: \"grant_id_required\" }, 400);\n\t\tconst config = readCoordinatorSyncConfig();\n\t\ttry {\n\t\t\tconst ok = await coordinatorRevokeBootstrapGrantAction({\n\t\t\t\tgrantId,\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!ok) return c.json({ error: \"grant_not_found\" }, 404);\n\t\t\treturn c.json({ ok: true, grant_id: grantId });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : \"unknown\";\n\t\t\treturn c.json({ error: message }, 500);\n\t\t}\n\t});\n\n\t// DELETE /api/sync/peers/:peer_device_id\n\tapp.delete(\"/api/sync/peers/:peer_device_id\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst peerDeviceId = c.req.param(\"peer_device_id\")?.trim();\n\t\t\tif (!peerDeviceId) return c.json({ error: \"peer_device_id required\" }, 400);\n\t\t\tconst exists = d\n\t\t\t\t.select({ peer_device_id: schema.syncPeers.peer_device_id })\n\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t\t.get();\n\t\t\tif (!exists) return c.json({ error: \"peer not found\" }, 404);\n\t\t\td.delete(schema.replicationCursors)\n\t\t\t\t.where(eq(schema.replicationCursors.peer_device_id, peerDeviceId))\n\t\t\t\t.run();\n\t\t\td.delete(schema.syncPeers).where(eq(schema.syncPeers.peer_device_id, peerDeviceId)).run();\n\t\t\treturn c.json({ ok: true });\n\t\t}\n\t});\n\n\treturn app;\n}\n","/**\n * @codemem/server — HTTP server (viewer, sync, API).\n *\n * Single HTTP server handling viewer routes and sync daemon.\n * Shares one better-sqlite3 connection between viewer and sync.\n * Embedding inference runs in a worker_thread (lazy-started).\n *\n * Entry: `codemem serve`\n */\n\nimport { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ObserverClient } from \"@codemem/core\";\nimport { MemoryStore, type RawEventSweeper, resolveDbPath, VERSION } from \"@codemem/core\";\nimport { serveStatic } from \"@hono/node-server/serve-static\";\nimport { Hono } from \"hono\";\nimport { originGuard, preflightHandler } from \"./middleware.js\";\nimport {\n\tcreateInMemoryRequestRateLimiter,\n\ttype InMemoryRequestRateLimiter,\n} from \"./request-rate-limit.js\";\nimport { configRoutes } from \"./routes/config.js\";\nimport { memoryRoutes } from \"./routes/memory.js\";\nimport { observerStatusRoutes } from \"./routes/observer-status.js\";\nimport { rawEventsRoutes } from \"./routes/raw-events.js\";\nimport { statsRoutes } from \"./routes/stats.js\";\nimport { syncProtocolRoutes, syncRoutes } from \"./routes/sync.js\";\n\nexport { VERSION };\n\n/** Shared store instance — SQLite WAL mode handles concurrent reads safely. */\nlet sharedStore: MemoryStore | null = null;\n\n/** Get (or create) the shared store instance. Exported so the sweeper can share it. */\nexport function getStore(): MemoryStore {\n\tif (!sharedStore) {\n\t\tsharedStore = new MemoryStore(resolveDbPath());\n\t}\n\treturn sharedStore;\n}\n\n/** Close the shared store (called on shutdown). */\nexport function closeStore(): void {\n\tsharedStore?.close();\n\tsharedStore = null;\n}\n\n/**\n * Create the Hono app with all viewer routes.\n * Exported for testing — pass a custom store factory to inject test DBs.\n */\nexport interface AppOptions {\n\tstoreFactory?: () => MemoryStore;\n\tsweeper?: RawEventSweeper | null;\n\tobserver?: ObserverClient | null;\n\tsyncRequestRateLimit?: {\n\t\tlimiter?: InMemoryRequestRateLimiter;\n\t\treadLimit?: number;\n\t\tmutationLimit?: number;\n\t\tunauthenticatedReadLimit?: number;\n\t\tunauthenticatedMutationLimit?: number;\n\t};\n\tgetSyncRuntimeStatus?: () => {\n\t\tphase:\n\t\t\t| \"starting\"\n\t\t\t| \"running\"\n\t\t\t| \"stopping\"\n\t\t\t| \"error\"\n\t\t\t| \"disabled\"\n\t\t\t| \"rebootstrapping\"\n\t\t\t| \"needs_attention\"\n\t\t\t| null;\n\t\tdetail?: string | null;\n\t} | null;\n}\n\nexport function createApp(opts?: AppOptions) {\n\tconst storeFactory = opts?.storeFactory ?? getStore;\n\tconst sweeper = opts?.sweeper ?? null;\n\tconst observer = opts?.observer ?? null;\n\tconst getSyncRuntimeStatus = opts?.getSyncRuntimeStatus ?? (() => null);\n\tconst app = new Hono();\n\n\t// CORS / origin guard\n\tapp.use(\"*\", preflightHandler());\n\tapp.use(\"*\", originGuard());\n\n\t// API routes\n\tapp.route(\"/\", statsRoutes(storeFactory));\n\tapp.route(\"/\", memoryRoutes(storeFactory));\n\tapp.route(\n\t\t\"/\",\n\t\tobserverStatusRoutes({\n\t\t\tgetStore: storeFactory,\n\t\t\tgetSweeper: () => sweeper,\n\t\t\tgetObserver: () => observer,\n\t\t}),\n\t);\n\tapp.route(\"/\", configRoutes({ getSweeper: () => sweeper }));\n\tapp.route(\"/\", rawEventsRoutes(storeFactory, sweeper));\n\tapp.route(\"/\", syncRoutes(storeFactory, getSyncRuntimeStatus));\n\n\t// Static assets — serve under /assets/*\n\t// Resolves to packages/viewer-server/static/ both in dev and when installed from npm.\n\tconst staticRoot =\n\t\tprocess.env.CODEMEM_VIEWER_STATIC_DIR ?? join(import.meta.dirname ?? \".\", \"../static\");\n\n\tapp.use(\n\t\t\"/assets/*\",\n\t\tserveStatic({\n\t\t\troot: staticRoot,\n\t\t\trewriteRequestPath: (path) => path.replace(/^\\/assets/, \"\"),\n\t\t}),\n\t);\n\n\t// SPA — serve index.html for root and all client-side routes\n\tconst indexPath = join(staticRoot, \"index.html\");\n\tif (!existsSync(indexPath)) {\n\t\tthrow new Error(\n\t\t\t`Viewer assets missing at ${indexPath}. Run \\`pnpm build\\` from the repo root before starting the viewer.`,\n\t\t);\n\t}\n\tconst indexHtml = readFileSync(indexPath, \"utf-8\");\n\tapp.get(\"*\", (c) => {\n\t\tif (c.req.path.startsWith(\"/api/\")) {\n\t\t\treturn c.json({ error: \"not found\" }, 404);\n\t\t}\n\t\treturn c.html(indexHtml);\n\t});\n\n\treturn app;\n}\n\n/**\n * Create the Hono app for peer-to-peer sync protocol routes only.\n *\n * This app is bound to a separate network-accessible listener\n * (default 0.0.0.0:7337) so remote peers can reach the sync\n * endpoints without exposing the viewer UI or local API routes.\n *\n * No CORS/origin guard is applied — sync requests are authenticated\n * via cryptographic signature verification instead.\n */\nexport function createSyncApp(opts?: AppOptions) {\n\tconst storeFactory = opts?.storeFactory ?? getStore;\n\tconst requestRateLimit = opts?.syncRequestRateLimit ?? {};\n\tconst rateLimiter = requestRateLimit.limiter ?? createInMemoryRequestRateLimiter();\n\tconst readLimit = Math.max(1, Math.trunc(requestRateLimit.readLimit ?? 120));\n\tconst mutationLimit = Math.max(1, Math.trunc(requestRateLimit.mutationLimit ?? 30));\n\tconst app = new Hono();\n\tapp.route(\n\t\t\"/\",\n\t\tsyncProtocolRoutes(storeFactory, {\n\t\t\trouteRateLimit: {\n\t\t\t\tlimiter: rateLimiter,\n\t\t\t\treadLimit,\n\t\t\t\tmutationLimit,\n\t\t\t\tunauthenticatedReadLimit: Math.max(\n\t\t\t\t\t1,\n\t\t\t\t\tMath.trunc(requestRateLimit.unauthenticatedReadLimit ?? Math.min(20, readLimit)),\n\t\t\t\t),\n\t\t\t\tunauthenticatedMutationLimit: Math.max(\n\t\t\t\t\t1,\n\t\t\t\t\tMath.trunc(requestRateLimit.unauthenticatedMutationLimit ?? Math.min(10, mutationLimit)),\n\t\t\t\t),\n\t\t\t},\n\t\t}),\n\t);\n\n\t// Catch-all — return generic 404 to avoid fingerprinting the server.\n\tapp.all(\"*\", (c) => c.json({ error: \"not found\" }, 404));\n\n\treturn app;\n}\n\n// No auto-start — the CLI's `serve` command owns server startup.\n"],"mappings":";;;;;;;;;;;;;AAYA,IAAM,iBAAiB,IAAI,IAAI;CAAC;CAAa;CAAa;CAAM,CAAC;;;;;AAMjE,SAAS,iBAAiB,QAAyB;CAClD,IAAI;AACJ,KAAI;AACH,QAAM,IAAI,IAAI,OAAO;SACd;AACP,SAAO;;AAER,KAAI,IAAI,aAAa,WAAW,IAAI,aAAa,SAAU,QAAO;AAClE,KAAI,IAAI,YAAY,IAAI,SAAU,QAAO;AACzC,QAAO,eAAe,IAAI,IAAI,SAAS;;;AAIxC,IAAM,iBAAiB,IAAI,IAAI;CAAC;CAAQ;CAAU;CAAS;CAAM,CAAC;;;;;;;;;AAUlE,SAAS,sBAAsB,GAAqB;CACnD,MAAM,gBAAgB,EAAE,IAAI,OAAO,iBAAiB,IAAI,IAAI,MAAM,CAAC,aAAa;AAChF,KAAI,gBAAgB,CAAC;EAAC;EAAe;EAAa;EAAO,CAAC,SAAS,aAAa,CAC/E,QAAO;CAER,MAAM,UAAU,EAAE,IAAI,OAAO,UAAU;AACvC,KAAI,CAAC,QAAS,QAAO;AACrB,QAAO,CAAC,iBAAiB,QAAQ;;;;;;;;;;;;;;;;;;AAmBlC,SAAgB,cAAc;AAC7B,QAAO,iBAAiB,OAAO,GAAY,SAAe;EACzD,MAAM,SAAS,EAAE,IAAI,OAAO,SAAS;EACrC,MAAM,SAAS,EAAE,IAAI;AAErB,MAAI,eAAe,IAAI,OAAO;OACzB,QAAQ;AAEX,QAAI,CAAC,iBAAiB,OAAO,CAC5B,QAAO,EAAE,KAAK,EAAE,OAAO,aAAa,EAAE,IAAI;AAG3C,MAAE,OAAO,+BAA+B,OAAO;AAC/C,MAAE,OAAO,gCAAgC,6BAA6B;AACtE,MAAE,OAAO,gCAAgC,eAAe;cAIpD,sBAAsB,EAAE,CAC3B,QAAO,EAAE,KAAK,EAAE,OAAO,aAAa,EAAE,IAAI;aAIlC,UAAU,iBAAiB,OAAO,EAAE;AAE9C,KAAE,OAAO,+BAA+B,OAAO;AAC/C,KAAE,OAAO,gCAAgC,6BAA6B;AACtE,KAAE,OAAO,gCAAgC,eAAe;;AAKzD,QAAM,MAAM;GACX;;;;;;AAOH,SAAgB,mBAAmB;AAClC,QAAO,iBAAiB,OAAO,GAAY,SAAe;AACzD,MAAI,EAAE,IAAI,WAAW,WAAW;AAC/B,SAAM,MAAM;AACZ;;EAED,MAAM,SAAS,EAAE,IAAI,OAAO,SAAS;AACrC,MAAI,UAAU,iBAAiB,OAAO,EAAE;AACvC,KAAE,OAAO,+BAA+B,OAAO;AAC/C,KAAE,OAAO,gCAAgC,6BAA6B;AACtE,KAAE,OAAO,gCAAgC,eAAe;AACxD,KAAE,OAAO,0BAA0B,QAAQ;AAC3C,UAAO,EAAE,KAAK,MAAM,IAAI;;AAEzB,SAAO,EAAE,KAAK,MAAM,IAAI;GACvB;;;;ACpHH,SAAgB,iCAAiC,WAAW,KAAoC;CAC/F,MAAM,eAAe,KAAK,IAAI,KAAM,KAAK,MAAM,SAAS,CAAC;CACzD,MAAM,0BAAU,IAAI,KAA2D;CAC/E,IAAI,SAAS;CAEb,SAAS,qBAAqB,OAAuB;AACpD,SAAO,KAAK,IAAI,GAAG,KAAK,KAAK,eAAe,KAAK,IAAI,GAAG,MAAM,GAAG,IAAK,CAAC;;CAGxE,SAAS,sBAAsB,YAA0B;AACxD,MAAI,QAAQ,OAAO,MAAM,SAAS,OAAO,EAAG;EAC5C,MAAM,cAAc,aAAa,eAAe;AAChD,OAAK,MAAM,CAAC,KAAK,WAAW,QAC3B,KAAI,OAAO,aAAa,YAAa,SAAQ,OAAO,IAAI;;AAI1D,QAAO,EACN,MAAM,KAAa,OAAe;AACjC,YAAU;EACV,MAAM,aAAa,KAAK,KAAK;AAC7B,wBAAsB,WAAW;EACjC,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,MAAM,CAAC;EAChD,MAAM,YAAY,GAAG,UAAU,GAAG;EAClC,IAAI,SAAS,QAAQ,IAAI,UAAU;AACnC,MAAI,CAAC,QAAQ;AACZ,YAAS;IACR,SAAS,IAAI,YAAY;KACxB,mBAAmB;KACnB,UAAU;KACV,iBAAiB;KACjB,CAAC;IACF,YAAY;IACZ;AACD,WAAQ,IAAI,WAAW,OAAO;;AAE/B,SAAO,aAAa;AACpB,MAAI,OAAO,QAAQ,gBAAgB,EAAE,CACpC,QAAO;GAAE,SAAS;GAAM,aAAa;GAAG;AAEzC,SAAO;GAAE,SAAS;GAAO,aAAa,qBAAqB,UAAU;GAAE;IAExE;;;;;;;;;;ACvBF,IAAM,iBAAiB;AAEvB,IAAM,WAAW,IAAI,IAAI,CAAC,YAAY,iBAAiB,CAAC;AACxD,IAAM,eAAe,IAAI,IAAI;CAAC;CAAQ;CAAO;CAAQ;CAAW;CAAO,CAAC;AACxE,IAAM,kBAAkB,IAAI,IAAI,CAAC,gCAAgC,CAAC;AAClE,IAAM,uBAAuB,IAAI,IAAY;CAC5C;CACA;CACA;CACA;CACA;CACA;CACA,CAAU;AACX,IAAM,qBAAqB,IAAI,IAAY;CAC1C;CACA;CACA;CACA;CACA,CAAU;AACX,IAAM,eAAe;CACpB;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;CACA;AAED,IAAM,WAAuB;CAC5B,gBAAgB,CAAC,SAAS;CAC1B,kBAAkB;CAClB,sBAAsB;CACtB,+BAA+B;CAC/B,oCAAoC;CACpC,uBAAuB,EAAE;CACzB,0BAA0B;CAC1B,2BAA2B;CAC3B,kBAAkB,EAAE;CACpB,oBAAoB;CACpB,wBAAwB;CACxB,oBAAoB;CACpB,cAAc;CACd,wBAAwB;CACxB,6BAA6B;CAC7B,4BAA4B;CAC5B,WAAW;CACX,WAAW;CACX,iBAAiB;CACjB,WAAW;CACX,4BAA4B;CAC5B,iCAAiC;CACjC,+BAA+B;CAC/B;AAMD,SAAS,sBAAgC;AACxC,QAAO,6BAA6B;;AAGrC,SAAS,gBAAwB;CAChC,MAAM,UAAU,QAAQ,IAAI;AAC5B,KAAI,QAAS,QAAO,QAAQ,QAAQ,MAAM,SAAS,CAAC;CACpD,MAAM,YAAY,KAAK,SAAS,EAAE,WAAW,UAAU;AAEvD,QADmB,CAAC,KAAK,WAAW,cAAc,EAAE,KAAK,WAAW,eAAe,CAAC,CAClE,MAAM,MAAM,WAAW,EAAE,CAAC,IAAI,KAAK,WAAW,cAAc;;AAG/E,SAAS,eAAe,YAAgC;AACvD,KAAI,CAAC,WAAW,WAAW,CAAE,QAAO,EAAE;AACtC,KAAI;EACH,IAAI,OAAO,aAAa,YAAY,QAAQ,CAAC,MAAM;AACnD,MAAI,CAAC,KAAM,QAAO,EAAE;AACpB,MAAI;AACH,UAAO,KAAK,MAAM,KAAK;UAChB;AACP,UAAO,oBAAoB,kBAAkB,KAAK,CAAC;AACnD,UAAO,KAAK,MAAM,KAAK;;SAEjB;AACP,SAAO,EAAE;;;AAIX,SAAS,mBAAmB,YAAoC;CAC/D,MAAM,YAAwB;EAAE,GAAG;EAAU,GAAG;EAAY;AAC5D,MAAK,MAAM,CAAC,KAAK,WAAW,OAAO,QAAQ,6BAA6B,EAErE;EACF,MAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,OAAO,QAAQ,QAAQ,GAAI,WAAU,OAAO;;AAEjD,QAAO;;AAGR,SAAS,kBAAkB,KAAa,OAAyB;AAChE,KAAI,SAAS,QAAQ,CAAC,mBAAmB,IAAI,IAAI,CAAE,QAAO;AAC1D,KAAI,MAAM,QAAQ,MAAM,CAAE,QAAO,MAAM,SAAS,IAAI,iBAAiB,EAAE;AACvE,KAAI,OAAO,UAAU,SACpB,QAAO,OAAO,KAAK,MAAiC,CAAC,SAAS,IAAI,iBAAiB,EAAE;AAEtF,KAAI,OAAO,UAAU,SAAU,QAAO,MAAM,MAAM,GAAG,iBAAiB;AACtE,QAAO;;AAGR,SAAS,0BAA0B,YAAoC;CACtE,MAAM,YAAwB,EAAE;AAChC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,WAAW,CACpD,WAAU,OAAO,kBAAkB,KAAK,MAAM;AAE/C,QAAO;;AAGR,SAAS,kBAAkB,MAAe,OAAyB;AAClE,KAAI,OAAO,GAAG,MAAM,MAAM,CAAE,QAAO;AACnC,KAAI,QAAQ,QAAQ,SAAS,KAAM,QAAO,QAAQ,QAAQ,SAAS;AACnE,KAAI,OAAO,SAAS,YAAY,OAAO,UAAU,SAChD,QAAO,KAAK,UAAU,KAAK,KAAK,KAAK,UAAU,MAAM;AAEtD,QAAO;;AAGR,SAAS,uBACR,SACA,cACuD;CACvD,MAAM,iBAA6B,EAAE;AACrC,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,QAAQ,EAAE;AACnD,MAAI,CAAC,qBAAqB,IAAI,IAAI,EAAE;AACnC,kBAAe,OAAO;AACtB;;AAED,MAAI,mBAAmB,IAAI,IAAI,IAAI,UAAU,eAC5C;AAED,MAAI,kBAAkB,OAAO,aAAa,KAAK,CAC9C;AAED,SAAO;GACN,gBAAgB,EAAE;GAClB,OAAO,GAAG,IAAI;GACd;;AAEF,QAAO;EAAE;EAAgB,OAAO;EAAM;;AAGvC,SAAS,iBAAiB,OAAgB,YAAY,OAAsB;AAC3E,KAAI,OAAO,UAAU,UAAW,QAAO;CACvC,MAAM,SACL,OAAO,UAAU,WACd,QACA,OAAO,UAAU,YAAY,UAAU,KAAK,MAAM,MAAM,CAAC,GACxD,OAAO,MAAM,MAAM,CAAC,GACpB;AACL,KAAI,CAAC,OAAO,SAAS,OAAO,IAAI,CAAC,OAAO,UAAU,OAAO,CAAE,QAAO;AAClE,KAAI,UAAW,QAAO,UAAU,IAAI,SAAS;AAC7C,QAAO,SAAS,IAAI,SAAS;;AAG9B,SAAS,kBAAkB,OAAgB,YAAY,MAAqB;AAC3E,KAAI,OAAO,UAAU,UAAW,QAAO;CACvC,MAAM,SACL,OAAO,UAAU,WACd,QACA,OAAO,UAAU,YAAY,MAAM,MAAM,CAAC,SAAS,IAClD,OAAO,MAAM,MAAM,CAAC,GACpB;AACL,KAAI,CAAC,OAAO,SAAS,OAAO,CAAE,QAAO;AACrC,KAAI,UAAW,QAAO,UAAU,IAAI,SAAS;AAC7C,QAAO,SAAS,IAAI,SAAS;;AAG9B,SAAS,YAAY,OAA+C;AACnE,KAAI,SAAS,QAAQ,OAAO,UAAU,YAAY,MAAM,QAAQ,MAAM,CAAE,QAAO;CAC/E,MAAM,SAAiC,EAAE;AACzC,MAAK,MAAM,CAAC,KAAK,SAAS,OAAO,QAAQ,MAAM,EAAE;AAChD,MAAI,OAAO,SAAS,SAAU,QAAO;EACrC,MAAM,WAAW,IAAI,MAAM;AAC3B,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,YAAY;;AAEpB,QAAO;;AAGR,SAAS,iBAAiB,OAAiC;AAC1D,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO;CAClC,MAAM,OAAiB,EAAE;AACzB,MAAK,MAAM,QAAQ,OAAO;AACzB,MAAI,OAAO,SAAS,SAAU,QAAO;EACrC,MAAM,QAAQ,KAAK,MAAM;AACzB,MAAI,CAAC,MAAO,QAAO;AACnB,OAAK,KAAK,MAAM;;AAEjB,QAAO;;AAGR,SAAS,uBACR,YACA,KACA,OACA,WACgB;AAChB,KAAI,SAAS,QAAQ,UAAU,IAAI;AAClC,SAAO,WAAW;AAClB,SAAO;;AAER,KAAI,QAAQ,qBAAqB;AAChC,MAAI,OAAO,UAAU,SAAU,QAAO;EACtC,MAAM,WAAW,MAAM,MAAM,CAAC,aAAa;EAC3C,MAAM,eAAe,WAAW;EAChC,MAAM,kBAAkB,OAAO,iBAAiB,YAAY,aAAa,MAAM,CAAC,SAAS;AACzF,MAAI,CAAC,UAAU,IAAI,SAAS,IAAI,CAAC,gBAChC,QAAO;AAER,aAAW,OAAO;AAClB,SAAO;;AAER,KAAI,QAAQ,oBAAoB;AAC/B,MAAI,OAAO,UAAU,SAAU,QAAO;EACtC,MAAM,UAAU,MAAM,MAAM,CAAC,aAAa;AAC1C,MAAI,CAAC,SAAS,IAAI,QAAQ,CACzB,QAAO;AAER,aAAW,OAAO;AAClB,SAAO;;AAER,KAAI,QAAQ,wBAAwB;AACnC,MAAI,OAAO,UAAU,SAAU,QAAO;EACtC,MAAM,SAAS,MAAM,MAAM,CAAC,aAAa;AACzC,MAAI,CAAC,aAAa,IAAI,OAAO,CAC5B,QAAO;AAER,aAAW,OAAO;AAClB,SAAO;;AAER,KAAI,QAAQ,oBAAoB,QAAQ,yBAAyB;EAChE,MAAM,OAAO,iBAAiB,MAAM;AACpC,MAAI,QAAQ,KAAM,QAAO,GAAG,IAAI;AAChC,MAAI,KAAK,SAAS,EAAG,YAAW,OAAO;MAClC,QAAO,WAAW;AACvB,SAAO;;AAER,KAAI,QAAQ,oBAAoB;EAC/B,MAAM,UAAU,YAAY,MAAM;AAClC,MAAI,WAAW,KAAM,QAAO;AAC5B,MAAI,OAAO,KAAK,QAAQ,CAAC,SAAS,EAAG,YAAW,OAAO;MAClD,QAAO,WAAW;AACvB,SAAO;;AAER,KAAI,QAAQ,kBAAkB,QAAQ,4BAA4B,QAAQ,aAAa;AACtF,MAAI,OAAO,UAAU,UAAW,QAAO,GAAG,IAAI;AAC9C,aAAW,OAAO;AAClB,SAAO;;AAER,KAAI,QAAQ,mCAAmC,QAAQ,sCAAsC;AAC5F,MAAI,OAAO,UAAU,UAAW,QAAO,GAAG,IAAI;AAC9C,aAAW,OAAO;AAClB,SAAO;;AAER,KACC,QAAQ,uBACR,QAAQ,oBACR,QAAQ,2BACR,QAAQ,yBACR,QAAQ,oCACR,QAAQ,qCACR,QAAQ,wBACR,QAAQ,eACR,QAAQ,0BACR,QAAQ,0BACP;AACD,MAAI,OAAO,UAAU,SAAU,QAAO,GAAG,IAAI;EAC7C,MAAM,UAAU,MAAM,MAAM;AAC5B,MAAI,CAAC,QAAS,QAAO,WAAW;MAC3B,YAAW,OAAO;AACvB,SAAO;;AAER,KAAI,QAAQ,iCAAiC,QAAQ,6BAA6B;EACjF,MAAM,SAAS,kBAAkB,OAAO,KAAK;AAC7C,MAAI,UAAU,KAAM,QAAO,GAAG,IAAI;AAClC,aAAW,OAAO;AAClB,SAAO;;CAER,MAAM,YAAY,QAAQ;CAC1B,MAAM,SAAS,iBAAiB,OAAO,UAAU;AACjD,KAAI,UAAU,KAAM,QAAO,GAAG,IAAI,WAAW,YAAY,qBAAqB;AAC9E,YAAW,OAAO;AAClB,QAAO;;AAGR,SAAS,oBAAoB,aAAuB,MAAoC;CACvF,MAAM,UAAoB,EAAE;AAC5B,KAAI,YAAY,SAAS,gCAAgC,EAAE;EAC1D,MAAM,cAAc,uBAAuB,CAAC;EAC5C,MAAM,UACL,OAAO,gBAAgB,WACpB,cACA,OAAO,SAAS,OAAO,eAAe,GAAG,EAAE,GAAG;AAClD,MAAI,OAAO,SAAS,QAAQ,IAAI,UAAU,EACzC,SAAQ,IAAI,yCAAyC,OAAO,UAAU,IAAK;MAE3E,QAAO,QAAQ,IAAI;AAEpB,OAAK,cAAc,EAAE,qBAAqB;AAC1C,UAAQ,KAAK,gCAAgC;;AAE9C,QAAO;;AAGR,SAAgB,aAAa,OAA2B,EAAE,EAAE;CAC3D,MAAM,MAAM,IAAI,MAAM;AAEtB,KAAI,IAAI,gBAAgB,MAAM;EAC7B,MAAM,aAAa,eAAe;EAClC,MAAM,aAAa,eAAe,WAAW;EAC7C,MAAM,YAAY,mBAAmB,WAAW;AAChD,SAAO,EAAE,KAAK;GACb,MAAM;GACN,QAAQ,0BAA0B,WAAW;GAC7C,UAAU;GACV,WAAW,0BAA0B,UAAU;GAC/C,eAAe,wBAAwB;GACvC,gBAAgB,CAAC,GAAG,qBAAqB,CAAC,MAAM;GAChD,WAAW,qBAAqB;GAChC,CAAC;GACD;AAEF,KAAI,KAAK,eAAe,OAAO,MAAM;EACpC,IAAI;AACJ,MAAI;AACH,aAAW,MAAM,EAAE,IAAI,MAAM;UACtB;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;AAE9C,MAAI,WAAW,QAAQ,OAAO,YAAY,YAAY,MAAM,QAAQ,QAAQ,CAC3E,QAAO,EAAE,KAAK,EAAE,OAAO,6BAA6B,EAAE,IAAI;AAE3D,MACC,YAAY,WACX,QAAuB,UAAU,SACjC,OAAQ,QAAuB,WAAW,YAC1C,MAAM,QAAS,QAAuB,OAAO,EAE9C,QAAO,EAAE,KAAK,EAAE,OAAO,4BAA4B,EAAE,IAAI;EAE1D,MAAM,UACL,YAAY,WACX,QAAuB,UAAU,QAClC,OAAQ,QAAuB,WAAW,YAC1C,CAAC,MAAM,QAAS,QAAuB,OAAO,GACzC,QAAuB,SACxB;EAEL,MAAM,aAAa,sBAAsB;EACzC,MAAM,eAAe,uBAAuB;EAC5C,MAAM,EAAE,gBAAgB,OAAO,sBAAsB,uBACpD,SACA,aACA;AACD,MAAI,kBACH,QAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,EAAE,IAAI;EAGjD,MAAM,kBAAkB,mBAAmB,aAAa;EACxD,MAAM,aAAyB,EAAE,GAAG,cAAc;EAClD,MAAM,YAAY,IAAI,IAAI,qBAAqB,CAAC;EAEhD,MAAM,cAAc,aAAa,QAAQ,QAAQ,OAAO,eAAe;AACvE,OAAK,MAAM,OAAO,cAAc;AAC/B,OAAI,EAAE,OAAO,gBAAiB;GAC9B,MAAM,QAAQ,uBAAuB,YAAY,KAAK,eAAe,MAAM,UAAU;AACrF,OAAI,MAAO,QAAO,EAAE,KAAK,EAAE,OAAO,EAAE,IAAI;;EAGzC,IAAI;AACJ,MAAI;AACH,eAAY,uBAAuB,YAAY,WAAW;UACnD;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,EAAE,IAAI;;EAGxD,MAAM,iBAAiB,mBAAmB,WAAW;EACrD,MAAM,mBAAmB,aAAa,QAAQ,QAAQ,aAAa,SAAS,WAAW,KAAK;EAC5F,MAAM,uBAAuB,aAAa,QACxC,QAAQ,gBAAgB,SAAS,eAAe,KACjD;EACD,MAAM,eAAe,wBAAwB;EAC7C,MAAM,mBAAmB,iBAAiB,QACxC,QAAQ,CAAC,qBAAqB,SAAS,IAAI,IAAI,OAAO,aACvD;EAID,MAAM,kBAAkB,oBAHG,CAC1B,GAAG,IAAI,IAAI;GAAC,GAAG;GAAa,GAAG;GAAkB,GAAG;GAAqB,CAAC,CAC1E,EAC+D,KAAK;EACrE,MAAM,sBAAsB,qBAAqB,QAC/C,QAAQ,CAAC,gBAAgB,IAAI,IAAI,IAAI,EAAE,OAAO,cAC/C;AAED,SAAO,EAAE,KAAK;GACb,MAAM;GACN,QAAQ,0BAA0B,WAAW;GAC7C,WAAW,0BAA0B,eAAe;GACpD,gBAAgB,CAAC,GAAG,qBAAqB,CAAC,MAAM;GAChD,SAAS;IACR,YAAY;IACZ,gBAAgB;IAChB,mBAAmB;IACnB,uBAAuB;IACvB,qBAAqB;IACrB,UAAU,iBAAiB,KACzB,QACA,GAAG,IAAI,8BAA8B,aAAa,KAAK,qEACxD;IACD;GACD,CAAC;GACD;AAEF,QAAO;;;;;;;;;;;;AC/cR,SAAgB,aAAa,KAA0C;AACtE,KAAI,OAAO,KAAM,QAAO,EAAE;AAC1B,KAAI;EACH,MAAM,SAAkB,KAAK,MAAM,IAAI;AACvC,MAAI,CAAC,MAAM,QAAQ,OAAO,CAAE,QAAO,EAAE;AACrC,SAAO,OAAO,QAAQ,SAAyB,OAAO,SAAS,SAAS;SACjE;AACP,SAAO,EAAE;;;;;;AAOX,SAAgB,SAAS,OAA2B,cAA8B;AACjF,KAAI,SAAS,KAAM,QAAO;CAC1B,MAAM,SAAS,mBAAmB,MAAM;AACxC,QAAO,UAAU,OAAO,eAAe;;;;;;AAOxC,SAAgB,UAAU,OAAoC;AAC7D,KAAI,SAAS,KAAM,QAAO;AAC1B,QAAO,UAAU,OAAO,UAAU,UAAU,UAAU;;;;ACVvD,SAAS,oBAAoB,OAA+B;AAC3D,KAAI,OAAO,UAAU,SAAU,QAAO;CACtC,MAAM,UAAU,MAAM,MAAM;AAC5B,QAAO,UAAU,UAAU;;AAG5B,SAAS,sBAAsB,OAAsC;CACpE,MAAM,iBAAiB,IAAI,IAAI,MAAM,kBAAkB,CAAC;AACxD,QAAO;EACN,SAAS,MAAM;EACf;EACA,UAAU,MAAM;EAChB,gBAAgB,IAAI,IAAI,MAAM,KAAK,iBAAiB,WAAW,eAAe,SAAS,CAAC;EACxF;;AAGF,SAAS,kBACR,KACA,WACA,WAAW,SAAU,IAAI,iBAA4B,KAAK,EAChD;CACV,MAAM,OAAO;CACb,MAAM,UAAU,oBAAoB,IAAI,SAAS,IAAI,oBAAoB,KAAK,SAAS;AACvF,KAAI,YAAY,UAAU,QAAS,QAAO;CAE1C,MAAM,WACL,oBAAoB,IAAI,iBAAiB,IAAI,oBAAoB,KAAK,iBAAiB;AACxF,KAAI,aAAa,UAAU,SAAU,QAAO;AAC5C,KAAI,YAAY,UAAU,eAAe,IAAI,SAAS,CAAE,QAAO;AAC/D,KAAI,WAAW,UAAU,eAAe,IAAI,QAAQ,CAAE,QAAO;AAE7D,QAAO;;AAGR,SAAS,mBACR,WACA,KAC0B;CAC1B,MAAM,WAAW,SAAU,IAAI,iBAA4B,KAAK;AAMhE,QAAO;EAJN,GAAG;EACH,MAAM,oBAAqB,IAAI,QAAsC,MAAM,IAAI,cAAc;EAC7F,eAAe;EAIf,eAAe,kBAAkB,KAAK,WAAW,SAAS;EAC1D;;;;;AAMF,SAAS,oBAAoB,OAAoB,OAAwC;CACxF,MAAM,aAAuB,EAAE;CAC/B,MAAM,uBAAO,IAAI,KAAa;AAC9B,MAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,QAAQ,KAAK;AACnB,MAAI,SAAS,KAAM;EACnB,MAAM,MAAM,OAAO,MAAM;AACzB,MAAI,OAAO,MAAM,IAAI,IAAI,KAAK,IAAI,IAAI,CAAE;AACxC,OAAK,IAAI,IAAI;AACb,aAAW,KAAK,IAAI;;AAErB,KAAI,WAAW,WAAW,EAAG;CAG7B,MAAM,OADI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,CAErC,OAAO;EACP,IAAI,OAAO,SAAS;EACpB,SAAS,OAAO,SAAS;EACzB,KAAK,OAAO,SAAS;EACrB,CAAC,CACD,KAAK,OAAO,SAAS,CACrB,MAAM,QAAQ,OAAO,SAAS,IAAI,WAAW,CAAC,CAC9C,KAAK;CAEP,MAAM,4BAAY,IAAI,KAA+C;AACrE,MAAK,MAAM,OAAO,MAAM;EACvB,MAAM,aAAa,OAAO,IAAI,WAAW,GAAG,CAAC,MAAM;EACnD,MAAM,UAAU,aAAa,gBAAgB,WAAW,GAAG;EAC3D,MAAM,MAAM,OAAO,IAAI,OAAO,GAAG;AACjC,YAAU,IAAI,IAAI,IAAI;GAAE;GAAS;GAAK,CAAC;;AAGxC,MAAK,MAAM,QAAQ,OAAO;EACzB,MAAM,MAAM,OAAO,KAAK,WAAW;AACnC,MAAI,OAAO,MAAM,IAAI,CAAE;EACvB,MAAM,SAAS,UAAU,IAAI,IAAI;AACjC,MAAI,CAAC,OAAQ;AACb,OAAK,YAAY,OAAO;AACxB,OAAK,QAAQ,OAAO;;;;;;;AAQtB,SAAS,gBAAgB,KAAqB;AAC7C,KAAI,IAAI,aAAa,CAAC,WAAW,SAAS,CAAE,QAAO;CACnD,MAAM,QAAQ,IAAI,QAAQ,OAAO,IAAI,CAAC,MAAM,IAAI;AAChD,QAAO,MAAM,MAAM,SAAS,MAAM;;AAGnC,SAAS,eAAe,KAAwD;CAC/E,MAAM,QAAQ,OAAO,OAAO,GAAG,CAC7B,MAAM,CACN,aAAa;AACf,KAAI,UAAU,UAAU,UAAU,SAAU,QAAO;;AAIpD,SAAS,gBACR,OACA,SAM4B;CAC5B,MAAM,UAAmC,EAAE;AAC3C,KAAI,QAAQ,QAAS,SAAQ,UAAU,QAAQ;AAC/C,KAAI,QAAQ,MAAO,SAAQ,kBAAkB,QAAQ;CAErD,MAAM,eAAe,8BAA8B,SAAS;EAC3D,SAAS,MAAM;EACf,UAAU,MAAM;EAChB,CAAC;CAEF,MAAM,QADU,CAAC,2BAA2B,GAAG,aAAa,QAAQ,CAC9C,KAAK,QAAQ;CACnC,MAAM,OAAO,aAAa,eACvB,wEACA;CAEH,MAAM,OAAO,MAAM,GACjB,QACA,8BAA8B,KAAK;YAC1B,MAAM;;sBAGf,CACA,IAAI,GAAG,aAAa,QAAQ,QAAQ,QAAQ,GAAG,QAAQ,OAAO;CAEhE,MAAM,YAAY,sBAAsB,MAAM;AAC9C,QAAO,KAAK,KAAK,QAAQ,mBAAmB,WAAW,IAAI,CAAC;;AAG7D,SAAS,sBAAoB,MAAwC;AACpE,QAAO,oBAAwB;EAC9B,MAAM,KAAK;EACX,UAAU,KAAK;EACf,CAAC;;AAGH,SAAS,iBACR,OACA,SAO4B;CAC5B,MAAM,WAAW,KAAK,IAAI,QAAQ,QAAQ,QAAQ,SAAS,IAAI,GAAG;CAClE,IAAI,YAAY;CAChB,MAAM,UAAqC,EAAE;AAE7C,QAAO,QAAQ,SAAS,QAAQ,SAAS,QAAQ,QAAQ,GAAG;EAC3D,MAAM,OAAO,gBAAgB,OAAO;GACnC,OAAO;GACP,QAAQ;GACR,SAAS,QAAQ;GACjB,OAAO,QAAQ;GACf,CAAC;AACF,MAAI,KAAK,WAAW,EAAG;AACvB,UAAQ,KAAK,GAAG,KAAK,OAAO,QAAQ,QAAQ,CAAC;AAC7C,MAAI,KAAK,SAAS,SAAU;AAC5B,eAAa,KAAK;;AAGnB,QAAO,QAAQ,MAAM,QAAQ,QAAQ,QAAQ,SAAS,QAAQ,QAAQ,EAAE;;AAGzE,SAAgB,aAAa,UAAwB;CACpD,MAAM,MAAM,IAAI,MAAM;AAGtB,KAAI,IAAI,kBAAkB,MAAM;EAC/B,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,QAAQ,SAAS,EAAE,IAAI,MAAM,QAAQ,EAAE,GAAG;GAQhD,MAAM,QAPI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,CAErC,QAAQ,CACR,KAAK,OAAO,SAAS,CACrB,QAAQ,KAAK,OAAO,SAAS,WAAW,CAAC,CACzC,MAAM,MAAM,CACZ,KAAK,CACY,KAAK,SAAS;IAChC,GAAG;IACH,eAAe,SAAS,IAAI,cAAc;IAC1C,EAAE;AACH,UAAO,EAAE,KAAK,EAAE,OAAO,CAAC;;GAExB;AAGF,KAAI,IAAI,kBAAkB,MAAM;EAC/B,MAAM,QAAQ,UAAU;EACxB;GAEC,MAAM,OADI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,CAErC,eAAe,EAAE,SAAS,OAAO,SAAS,SAAS,CAAC,CACpD,KAAK,OAAO,SAAS,CACrB,MAAM,UAAU,OAAO,SAAS,QAAQ,CAAC,CACzC,KAAK;GACP,MAAM,WAAW,CAChB,GAAG,IAAI,IACN,KACE,KAAK,MAAM,OAAO,EAAE,WAAW,GAAG,CAAC,MAAM,CAAC,CAC1C,QAAQ,MAAM,KAAK,CAAC,EAAE,aAAa,CAAC,WAAW,SAAS,CAAC,CACzD,KAAK,MAAM,gBAAgB,EAAE,CAAC,CAC9B,OAAO,QAAQ,CACjB,CACD,CAAC,MAAM;AACR,UAAO,EAAE,KAAK,EAAE,UAAU,CAAC;;GAE3B;AAGF,KAAI,IAAI,kBAAkB,MAAM;EAC/B,MAAM,SAAS,IAAI,IAAI,EAAE,IAAI,IAAI,CAAC;AAClC,SAAO,EAAE,SAAS,oBAAoB,UAAU,IAAI;GACnD;AAEF,KAAI,IAAI,sBAAsB,MAAM;EACnC,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,QAAQ,KAAK,IAAI,GAAG,SAAS,EAAE,IAAI,MAAM,QAAQ,EAAE,GAAG,CAAC;GAC7D,MAAM,SAAS,KAAK,IAAI,GAAG,SAAS,EAAE,IAAI,MAAM,SAAS,EAAE,EAAE,CAAC;GAG9D,MAAM,QAAQ,iBAAiB,OAAO;IACrC;IACA;IACA,SALe,EAAE,IAAI,MAAM,UAAU,IAAI,KAAA;IAMzC,OALa,eAAe,EAAE,IAAI,MAAM,QAAQ,CAAC;IAMjD,UAAU,SAAS,CAAC,sBAAoB,KAAK;IAC7C,CAAC;GACF,MAAM,UAAU,MAAM,SAAS;GAC/B,MAAM,SAAS,UAAU,MAAM,MAAM,GAAG,MAAM,GAAG;GACjD,MAAM,YAAY;AAClB,uBAAoB,OAAO,UAAU;AACrC,UAAO,EAAE,KAAK;IACb,OAAO;IACP,YAAY;KACX;KACA;KACA,aAAa,UAAU,SAAS,OAAO,SAAS;KAChD,UAAU;KACV;IACD,CAAC;;GAEF;AAGF,KAAI,IAAI,mBAAmB,MAAM;EAChC,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,QAAQ,KAAK,IAAI,GAAG,SAAS,EAAE,IAAI,MAAM,QAAQ,EAAE,GAAG,CAAC;GAC7D,MAAM,SAAS,KAAK,IAAI,GAAG,SAAS,EAAE,IAAI,MAAM,SAAS,EAAE,EAAE,CAAC;GAG9D,MAAM,QAAQ,iBAAiB,OAAO;IACrC;IACA;IACA,SALe,EAAE,IAAI,MAAM,UAAU,IAAI,KAAA;IAMzC,OALa,eAAe,EAAE,IAAI,MAAM,QAAQ,CAAC;IAMjD,UAAU,SAAS,sBAAoB,KAAK;IAC5C,CAAC;GACF,MAAM,UAAU,MAAM,SAAS;GAC/B,MAAM,SAAS,UAAU,MAAM,MAAM,GAAG,MAAM,GAAG;GACjD,MAAM,YAAY;AAClB,uBAAoB,OAAO,UAAU;AACrC,UAAO,EAAE,KAAK;IACb,OAAO;IACP,YAAY;KACX;KACA;KACA,aAAa,UAAU,SAAS,OAAO,SAAS;KAChD,UAAU;KACV;IACD,CAAC;;GAEF;AAGF,KAAI,IAAI,iBAAiB,MAAM;EAC9B,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,UAAU,EAAE,IAAI,MAAM,UAAU,IAAI;GAC1C,MAAM,SAAS,KAAa,GAAG,WAA8B;IAC5D,MAAM,MAAM,MAAM,GAAG,QAAQ,IAAI,CAAC,IAAI,GAAG,OAAO;AAChD,WAAO,OAAO,KAAK,SAAS,EAAE;;GAG/B,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,MAAM,qBAAqB,iBAA0B;IACpD,IAAI,SAAS;IACb,IAAI,QAAQ;AACZ,WAAO,MAAM;KACZ,MAAM,OAAO,gBAAgB,OAAO;MACnC,OAAO;MACP;MACA,SAAS;MACT,CAAC;AACF,SAAI,KAAK,WAAW,EAAG;AACvB,cAAS,KAAK,QAAQ,SAAS,CAAC,sBAAoB,KAAK,CAAC,CAAC;AAC3D,SAAI,KAAK,SAAS,IAAK;AACvB,eAAU,KAAK;;AAEhB,WAAO;;AAER,OAAI,SAAS;AACZ,cAAU,MAAM,gEAAgE,QAAQ;AACxF,gBAAY,MACX;;mCAGA,QACA;AACD,eAAW,MACV;;mCAGA,QACA;AACD,mBAAe,kBAAkB,QAAQ;UACnC;AACN,cAAU,MAAM,6CAA6C;AAC7D,gBAAY,MAAM,0CAA0C;AAC5D,eAAW,MAAM,6CAA6C;AAC9D,mBAAe,mBAAmB;;GAEnC,MAAM,QAAQ,UAAU,YAAY;AACpC,UAAO,EAAE,KAAK;IAAE;IAAO;IAAU;IAAW;IAAS;IAAc,CAAC;;GAEpE;AAGF,KAAI,IAAI,aAAa,OAAO,MAAM;EACjC,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,UAAU,EAAE,IAAI,MAAM,UAAU,IAAI;AAC1C,OAAI,CAAC,QACJ,QAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,EAAE,IAAI;GAElD,MAAM,QAAQ,SAAS,EAAE,IAAI,MAAM,QAAQ,EAAE,GAAG;GAChD,MAAM,iBAAiB,EAAE,IAAI,MAAM,eAAe;GAClD,IAAI;AACJ,OAAI,gBAAgB;AACnB,kBAAc,mBAAmB,eAAe,IAAI,KAAA;AACpD,QAAI,gBAAgB,KAAA,EACnB,QAAO,EAAE,KAAK,EAAE,OAAO,4BAA4B,EAAE,IAAI;;GAG3D,MAAM,UAAU,EAAE,IAAI,MAAM,UAAU,IAAI,KAAA;GAC1C,MAAM,UAAgC,EAAE;AACxC,OAAI,QAAS,SAAQ,UAAU;GAC/B,MAAM,OAAO,MAAM,MAAM,qBAAqB,SAAS,OAAO,eAAe,MAAM,QAAQ;AAC3F,UAAO,EAAE,KAAK,KAAK;;GAEnB;AAEF,KAAI,KAAK,mBAAmB,OAAO,MAAM;EACxC,MAAM,QAAQ,UAAU;EACxB,MAAM,SAAS,MAAM,EAAE,IAAI,MAAM,CAAC,YAAY,OAAO,IAAI,eAAe,CAAC;AACzE,MAAI,WAAW,OAAO,IAAI,eAAe,CACxC,QAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,EAAE,IAAI;EAEnD,MAAM,OAAO;EAOb,MAAM,UAAU,OAAO,MAAM,YAAY,WAAW,KAAK,QAAQ,MAAM,GAAG;AAC1E,MAAI,CAAC,QACJ,QAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,EAAE,IAAI;EAElD,MAAM,QACL,MAAM,SAAS,OACZ,KACA,OAAO,KAAK,UAAU,YAAY,OAAO,UAAU,KAAK,MAAM,IAAI,KAAK,SAAS,IAC/E,KAAK,QACL;AACL,MAAI,SAAS,KACZ,QAAO,EAAE,KAAK,EAAE,OAAO,gCAAgC,EAAE,IAAI;EAE9D,IAAI,cAA6B;AACjC,MAAI,MAAM,gBAAgB,MAAM;AAC/B,OACC,OAAO,KAAK,iBAAiB,YAC7B,CAAC,OAAO,UAAU,KAAK,aAAa,IACpC,KAAK,eAAe,EAEpB,QAAO,EAAE,KAAK,EAAE,OAAO,4BAA4B,EAAE,IAAI;AAE1D,iBAAc,KAAK;;EAEpB,MAAM,UAAU,OAAO,MAAM,YAAY,YAAY,KAAK,QAAQ,MAAM,GAAG,KAAK,UAAU;AAC1F,MAAI,MAAM,qBAAqB,QAAQ,CAAC,MAAM,QAAQ,KAAK,kBAAkB,CAC5E,QAAO,EAAE,KAAK,EAAE,OAAO,iDAAiD,EAAE,IAAI;AAE/E,MACC,MAAM,QAAQ,MAAM,kBAAkB,IACtC,KAAK,kBAAkB,MAAM,UAAU,OAAO,UAAU,SAAS,CAEjE,QAAO,EAAE,KAAK,EAAE,OAAO,iDAAiD,EAAE,IAAI;EAE/E,MAAM,kBAAkB,MAAM,QAAQ,MAAM,kBAAkB,GAAG,KAAK,oBAAoB,EAAE;EAC5F,MAAM,UAA8D,EAAE;AACtE,MAAI,QAAS,SAAQ,UAAU;AAC/B,MAAI,gBAAgB,SAAS,EAAG,SAAQ,oBAAoB;EAC5D,MAAM,QAAQ,MAAM,MAAM,0BAA0B,SAAS,OAAO,aAAa,QAAQ;AACzF,SAAO,EAAE,KAAK,MAAM;GACnB;AAGF,KAAI,IAAI,gBAAgB,MAAM;EAC7B,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,QAAQ,SAAS,EAAE,IAAI,MAAM,QAAQ,EAAE,GAAG;GAChD,MAAM,OAAO,EAAE,IAAI,MAAM,OAAO,IAAI,KAAA;GACpC,MAAM,UAAU,EAAE,IAAI,MAAM,UAAU,IAAI,KAAA;GAC1C,MAAM,UAAmC,EAAE;AAC3C,OAAI,KAAM,SAAQ,OAAO;AACzB,OAAI,QAAS,SAAQ,UAAU;GAE/B,MAAM,YADQ,MAAM,OAAO,OAAO,QAAQ;AAE1C,uBAAoB,OAAO,UAAU;AACrC,UAAO,EAAE,KAAK,EAAE,OAAO,WAAW,CAAC;;GAEnC;AAGF,KAAI,IAAI,mBAAmB,MAAM;EAChC,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,eAAe,EAAE,IAAI,MAAM,aAAa;AAC9C,OAAI,CAAC,aACJ,QAAO,EAAE,KAAK,EAAE,OAAO,uBAAuB,EAAE,IAAI;GAErD,MAAM,YAAY,mBAAmB,aAAa;AAClD,OAAI,aAAa,KAChB,QAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,EAAE,IAAI;GAGxD,MAAM,OADI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,CAErC,QAAQ,CACR,KAAK,OAAO,UAAU,CACtB,MAAM,GAAG,OAAO,UAAU,YAAY,UAAU,CAAC,CACjD,KAAK;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,MAAM,CAAC;;GAE9B;AAGF,KAAI,KAAK,4BAA4B,OAAO,MAAM;EACjD,MAAM,QAAQ,UAAU;EACxB,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,WAAW,mBAChB,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY,OAAO,KAAK,aAAa,GAAG,CAClF;AACD,MAAI,YAAY,QAAQ,YAAY,EACnC,QAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,EAAE,IAAI;EAEvD,MAAM,aAAa,OAAO,KAAK,cAAc,GAAG,CAAC,MAAM;AACvD,MAAI,eAAe,aAAa,eAAe,SAC9C,QAAO,EAAE,KAAK,EAAE,OAAO,wCAAwC,EAAE,IAAI;AAEtE,MAAI;GACH,MAAM,OAAO,MAAM,uBAAuB,UAAU,WAAW;AAC/D,UAAO,EAAE,KAAK,EAAE,MAAM,CAAC;WACf,KAAK;GACb,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,OAAI,IAAI,SAAS,YAAY,CAAE,QAAO,EAAE,KAAK,EAAE,OAAO,KAAK,EAAE,IAAI;AACjE,OAAI,IAAI,SAAS,YAAY,CAAE,QAAO,EAAE,KAAK,EAAE,OAAO,KAAK,EAAE,IAAI;AACjE,UAAO,EAAE,KAAK,EAAE,OAAO,KAAK,EAAE,IAAI;;GAElC;AAGF,KAAI,KAAK,wBAAwB,OAAO,MAAM;EAC7C,MAAM,QAAQ,UAAU;EACxB,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,WAAW,mBAChB,OAAO,KAAK,cAAc,WAAW,KAAK,YAAY,OAAO,KAAK,aAAa,GAAG,CAClF;AACD,MAAI,YAAY,QAAQ,YAAY,EACnC,QAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,EAAE,IAAI;EAGvD,MAAM,MAAM,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,CACvC,QAAQ,CACR,KAAK,OAAO,YAAY,CACxB,MAAM,GAAG,OAAO,YAAY,IAAI,SAAS,CAAC,CAC1C,KAAK;AACP,MAAI,CAAC,IACJ,QAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,EAAE,IAAI;AAGlD,MAAI,CAAC,kBAAkB,KADL,sBAAsB,MAAM,CACR,CACrC,QAAO,EAAE,KAAK,EAAE,OAAO,mCAAmC,EAAE,IAAI;AAEjE,MAAI,OAAO,IAAI,UAAU,EAAE,KAAK,KAAK,IAAI,cAAc,KACtD,QAAO,EAAE,KAAK,EAAE,QAAQ,MAAM,CAAC;AAGhC,MAAI;AACH,SAAM,OAAO,SAAS;AACtB,UAAO,EAAE,KAAK,EAAE,QAAQ,MAAM,CAAC;WACvB,KAAK;GACb,MAAM,MAAM,eAAe,QAAQ,IAAI,UAAU,OAAO,IAAI;AAC5D,OAAI,IAAI,SAAS,YAAY,CAAE,QAAO,EAAE,KAAK,EAAE,OAAO,KAAK,EAAE,IAAI;AACjE,OAAI,IAAI,SAAS,YAAY,CAAE,QAAO,EAAE,KAAK,EAAE,OAAO,KAAK,EAAE,IAAI;AACjE,OAAI,IAAI,SAAS,+BAA+B,CAAE,QAAO,EAAE,KAAK,EAAE,OAAO,KAAK,EAAE,IAAI;AACpF,UAAO,EAAE,KAAK,EAAE,OAAO,KAAK,EAAE,IAAI;;GAElC;AAEF,QAAO;;;;AC5iBR,SAAS,wBAAwB,QAAwD;AACxF,KAAI,CAAC,OAAQ,QAAO;AACpB,QAAO;EACN,GAAG;EACH,MAAM;GACL,GAAG,OAAO;GACV,QAAQ,OAAO,KAAK;GACpB,eAAe,OAAO,KAAK;GAC3B;EACD;;AAGF,SAAS,mBACR,eACA,aACA,aACgB;AAChB,KAAI,CAAC,cAAe,QAAO;AAC3B,KAAI,YAAY,OACf,QAAO,6BAA6B,YAAY,WAAW;AAE5D,KAAI,YAAY,UAAU,EACzB,QAAO,GAAG,YAAY,QAAQ,4BAA4B,YAAY,SAAS;AAEhF,QAAO;;AAGR,SAAgB,qBAAqB,MAA2B;CAC/D,MAAM,MAAM,IAAI,MAAM;AAEtB,KAAI,IAAI,yBAAyB,MAAM;EACtC,MAAM,QAAQ,MAAM,UAAU;EAC9B,MAAM,UAAU,MAAM,YAAY;EAClC,MAAM,WAAW,MAAM,eAAe,IAAI;AAG1C,MAAI,CAAC,SAAS,OAAO,MAAM,0BAA0B,WACpD,QAAO,EAAE,KAAK;GACb,QAAQ;GACR,uBAAuB,EAAE;GACzB,gBAAgB;GAChB,OAAO;IACN,SAAS;IACT,UAAU;IACV,qBAAqB;IACrB,0BAA0B;IAC1B;GACD,CAAC;EAGH,MAAM,cAAc,MAAM,uBAAuB;EACjD,MAAM,cAAc,SAAS,mBAAmB,IAAI;GAAE,QAAQ;GAAO,YAAY;GAAG;EACpF,MAAM,gBAAgB,MAAM,4BAA4B;EACxD,MAAM,SAAS,wBAAwB,UAAU,WAAW,IAAI,KAAK;EACrE,MAAM,uBAAuB,2BAA2B;EAIxD,MAAM,oBAFL,iBAAiB,SAAS,YAAY,UAAU,YAAY,UAAU,MAGjD,gBAClB;GAAE,GAAG;GAAe,QAAQ,mBAAmB,eAAe,aAAa,YAAY;GAAE,GACzF;AAEJ,SAAO,EAAE,KAAK;GACb;GACA,uBAAuB;GACvB,gBAAgB;GAChB,OAAO;IACN,GAAG;IACH,qBAAqB,YAAY;IACjC,0BAA0B,YAAY;IACtC;GACD,CAAC;GACD;AAEF,QAAO;;;;;;;;AC/ER,IAAM,4BACL,OAAO,SAAS,QAAQ,IAAI,qCAAqC,IAAI,GAAG,IAAI;;AAG7E,IAAM,kBAAkB;CACvB;CACA;CACA;CACA;CACA;;;;;AAMD,SAAS,uBAAuB,SAAiD;CAChF,MAAM,yBAAS,IAAI,KAAqB;AACxC,MAAK,MAAM,OAAO,iBAAiB;EAClC,MAAM,QAAQ,QAAQ;AACtB,MAAI,SAAS,KAAM;AACnB,MAAI,OAAO,UAAU,SAAU,OAAM,IAAI,MAAM,GAAG,IAAI,iBAAiB;EACvE,MAAM,OAAO,MAAM,MAAM;AACzB,MAAI,KAAM,QAAO,IAAI,KAAK,KAAK;;AAEhC,KAAI,OAAO,SAAS,EAAG,QAAO;AAE9B,KADe,IAAI,IAAI,OAAO,QAAQ,CAAC,CAC5B,OAAO,EAAG,OAAM,IAAI,MAAM,gCAAgC;AAErE,MAAK,MAAM,OAAO,iBAAiB;EAClC,MAAM,IAAI,OAAO,IAAI,IAAI;AACzB,MAAI,EAAG,QAAO;;AAEf,QAAO;;;;;;AAOR,eAAe,oBACd,GAIA,UAC8C;CAC9C,MAAM,gBAAgB,OAAO,SAAS,EAAE,IAAI,OAAO,iBAAiB,IAAI,KAAK,GAAG;AAChF,KAAI,OAAO,MAAM,cAAc,IAAI,gBAAgB,EAClD,QAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,EAAE,IAAI;AAExD,KAAI,gBAAgB,SACnB,QAAO,EAAE,KAAK;EAAE,OAAO;EAAqB,WAAW;EAAU,EAAE,IAAI;CAExE,IAAI;AACJ,KAAI;AACH,QAAM,MAAM,EAAE,IAAI,MAAM;SACjB;AACP,SAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;AAE9C,KAAI,OAAO,WAAW,KAAK,QAAQ,GAAG,SACrC,QAAO,EAAE,KAAK;EAAE,OAAO;EAAqB,WAAW;EAAU,EAAE,IAAI;CAExE,IAAI;AACJ,KAAI;AACH,WAAS,MAAM,KAAK,MAAM,IAAI,GAAG,EAAE;SAC5B;AACP,SAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;AAE9C,KAAI,UAAU,QAAQ,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,CACxE,QAAO,EAAE,KAAK,EAAE,OAAO,6BAA6B,EAAE,IAAI;AAE3D,QAAO;;;AAIR,SAAS,aACR,SACA,YACA,SAAS,YACF;AACP,KAAI;AACH,OAAK,MAAM,aAAa,WACvB,UAAS,MAAM,WAAW,OAAO;SAE3B;;AAKT,SAAgB,gBAAgB,UAAwB,SAAkC;CACzF,MAAM,MAAM,IAAI,MAAM;AAGtB,KAAI,IAAI,oBAAoB,MAAM;EAEjC,MAAM,SADQ,UAAU,CACH,uBAAuB;AAC5C,SAAO,EAAE,KAAK,OAAO;GACpB;AAGF,KAAI,IAAI,2BAA2B,MAAM;EACxC,MAAM,QAAQ,UAAU;EACxB,MAAM,QAAQ,SAAS,EAAE,IAAI,MAAM,QAAQ,EAAE,GAAG;EAmBhD,MAAM,QAlBI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC,CAErC,OAAO;GACP,QAAQ,OAAO,iBAAiB;GAChC,WAAW,OAAO,iBAAiB;GACnC,qBAAqB,OAAO,iBAAiB;GAC7C,KAAK,OAAO,iBAAiB;GAC7B,SAAS,OAAO,iBAAiB;GACjC,YAAY,OAAO,iBAAiB;GACpC,sBAAsB,OAAO,iBAAiB;GAC9C,yBAAyB,OAAO,iBAAiB;GACjD,wBAAwB,OAAO,iBAAiB;GAChD,YAAY,OAAO,iBAAiB;GACpC,CAAC,CACD,KAAK,OAAO,iBAAiB,CAC7B,QAAQ,KAAK,OAAO,iBAAiB,WAAW,CAAC,CACjD,MAAM,MAAM,CACZ,KAAK,CACY,KAAK,QAAQ;GAC/B,MAAM,WAAW,OAAO,IAAI,aAAa,IAAI,uBAAuB,GAAG;AACvE,UAAO;IACN,GAAG;IACH,mBAAmB;IACnB,YAAY;IACZ;IACA;EACF,MAAM,SAAS,MAAM,uBAAuB;AAC5C,SAAO,EAAE,KAAK;GACb;GACA;GACA,QAAQ;IACP,WAAW;IACX,MAAM;IACN,gBAAgB;IAChB;GACD,CAAC;GACD;AAGF,KAAI,KAAK,mBAAmB,OAAO,MAAM;EACxC,MAAM,SAAS,MAAM,oBAAoB,GAAG,0BAA0B;AACtE,MAAI,kBAAkB,SAAU,QAAO;EACvC,MAAM,UAAU;EAEhB,MAAM,QAAQ,UAAU;AACxB,MAAI;GAEH,MAAM,MAAM,QAAQ;AACpB,OAAI,OAAO,QAAQ,OAAO,QAAQ,SACjC,QAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,EAAE,IAAI;GAEpD,MAAM,UAAU,QAAQ;AACxB,OAAI,WAAW,QAAQ,OAAO,YAAY,SACzC,QAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,EAAE,IAAI;GAExD,MAAM,YAAY,QAAQ;AAC1B,OAAI,aAAa,QAAQ,OAAO,cAAc,SAC7C,QAAO,EAAE,KAAK,EAAE,OAAO,6BAA6B,EAAE,IAAI;GAI3D,IAAI,QAAQ,QAAQ;AACpB,OAAI,SAAS,KACZ,SAAQ,CAAC,QAAQ;AAElB,OAAI,CAAC,MAAM,QAAQ,MAAM,CACxB,QAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,EAAE,IAAI;GAIvD,IAAI;AACJ,OAAI;AACH,uBAAmB,uBAAuB,QAAQ,IAAI;YAC9C,KAAK;AACb,WAAO,EAAE,KAAK,EAAE,OAAQ,IAAc,SAAS,EAAE,IAAI;;AAEtD,OAAI,iBAAiB,WAAW,OAAO,CACtC,QAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,EAAE,IAAI;GAGpD,IAAI,WAAW;GACf,MAAM,oCAAoB,IAAI,KAAqB;GACnD,MAAM,gCAAgB,IAAI,KAAqC;GAC/D,MAAM,6BAAa,IAAI,KAAa;GACpC,MAAM,iCAAiB,IAAI,KAAwC;AAEnE,QAAK,MAAM,QAAQ,OAAO;AACzB,QAAI,QAAQ,QAAQ,OAAO,SAAS,YAAY,MAAM,QAAQ,KAAK,CAClE,QAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;IAEzD,MAAM,UAAU;IAEhB,IAAI;AACJ,QAAI;AACH,qBAAgB,uBAAuB,QAAQ;aACvC,KAAK;AACb,YAAO,EAAE,KAAK,EAAE,OAAQ,IAAc,SAAS,EAAE,IAAI;;IAEtD,MAAM,oBAAoB,OAAO,iBAAiB,oBAAoB,GAAG;AACzE,QAAI,CAAC,kBACJ,QAAO,EAAE,KAAK,EAAE,OAAO,uBAAuB,EAAE,IAAI;AAErD,QAAI,kBAAkB,WAAW,OAAO,CACvC,QAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,EAAE,IAAI;IAGpD,IAAI,UAAU,OAAO,QAAQ,YAAY,GAAG;IAC5C,MAAM,YAAY,OAAO,QAAQ,cAAc,GAAG;AAClD,QAAI,CAAC,UACJ,QAAO,EAAE,KAAK,EAAE,OAAO,uBAAuB,EAAE,IAAI;IAGrD,MAAM,gBAAgB,QAAQ;AAC9B,QAAI,iBAAiB,MAAM;KAC1B,MAAM,SAAS,OAAO,cAAc;AACpC,SAAI,CAAC,OAAO,SAAS,OAAO,IAAI,WAAW,KAAK,MAAM,OAAO,CAC5D,QAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,EAAE,IAAI;;IAIxD,IAAI,WAAW,QAAQ;AACvB,QAAI,YAAY,MAAM;KACrB,MAAM,SAAS,OAAO,SAAS;AAC/B,SAAI,CAAC,OAAO,SAAS,OAAO,CAC3B,QAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,EAAE,IAAI;AAExD,gBAAW,KAAK,MAAM,OAAO;KAC7B,MAAM,OAAO,kBAAkB,IAAI,kBAAkB,IAAK;AAC1D,uBAAkB,IAAI,mBAAmB,KAAK,IAAI,MAAM,SAAmB,CAAC;;IAG7E,IAAI,WAAW,QAAQ;AACvB,QAAI,YAAY,MAAM;KACrB,MAAM,SAAS,OAAO,SAAS;AAC/B,SAAI,CAAC,OAAO,SAAS,OAAO,CAC3B,QAAO,EAAE,KAAK,EAAE,OAAO,6BAA6B,EAAE,IAAI;AAE3D,gBAAW;;IAGZ,IAAI,eAAe,QAAQ;AAC3B,QAAI,gBAAgB,KAAM,gBAAe,EAAE;AAC3C,QAAI,OAAO,iBAAiB,YAAY,MAAM,QAAQ,aAAa,CAClE,QAAO,EAAE,KAAK,EAAE,OAAO,6BAA6B,EAAE,IAAI;IAI3D,MAAM,UAAU,QAAQ;AACxB,QAAI,WAAW,QAAQ,OAAO,YAAY,SACzC,QAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,EAAE,IAAI;IAEpD,MAAM,cAAc,QAAQ;AAC5B,QAAI,eAAe,QAAQ,OAAO,gBAAgB,SACjD,QAAO,EAAE,KAAK,EAAE,OAAO,0BAA0B,EAAE,IAAI;IAExD,MAAM,gBAAgB,QAAQ;AAC9B,QAAI,iBAAiB,QAAQ,OAAO,kBAAkB,SACrD,QAAO,EAAE,KAAK,EAAE,OAAO,6BAA6B,EAAE,IAAI;AAI3D,mBAAe,gBAAgB,aAAa;AAK5C,QAAI,CAAC,SAAS;KACb,MAAM,mBAAmB,QACxB,KAAK,UAAU,MAAM,MAAM,UAAU;AACpC,UAAI,SAAS,QAAQ,OAAO,UAAU,YAAY,CAAC,MAAM,QAAQ,MAAM,EAAE;OACxE,MAAM,SAAkC,EAAE;AAC1C,YAAK,MAAM,KAAK,OAAO,KAAK,MAAiC,CAAC,MAAM,CACnE,QAAO,KAAM,MAAkC;AAEhD,cAAO;;AAER,aAAO;OACN;AACH,SAAI,iBAAiB,MAAM;MAC1B,MAAM,QAAQ,gBAAgB;OAC7B,GAAG;OACH,GAAG;OACH,GAAG;OACH,CAAC;AAEF,gBAAU,cAAc,cAAc,GADzB,WAAW,SAAS,CAAC,OAAO,OAAO,QAAQ,CAAC,OAAO,MAAM,CAAC,MAAM,GAAG,GAAG;YAE7E;MACN,MAAM,QAAQ,gBAAgB;OAC7B,GAAG,YAAY;OACf,GAAG;OACH,GAAG;OACH,GAAG,YAAY;OACf,CAAC;AACF,gBAAU,UAAU,WAAW,SAAS,CAAC,OAAO,OAAO,QAAQ,CAAC,OAAO,MAAM,CAAC,MAAM,GAAG,GAAG;;;IAI5F,MAAM,aAAsC;KAC3C,UAAU;KACV,YAAY;KACZ,SAAS;KACT,YAAY,YAAY;KACxB,YAAY,YAAY;KACxB;AAED,eAAW,IAAI,kBAAkB;IACjC,MAAM,OAAO,eAAe,IAAI,kBAAkB,IAAI,EAAE;AACxD,SAAK,KAAK,EAAE,GAAG,YAAY,CAAC;AAC5B,mBAAe,IAAI,mBAAmB,KAAK;AAE3C,QAAI,WAAW,eAAe,eAAe;KAC5C,MAAM,aAAa,cAAc,IAAI,kBAAkB,IAAI,EAAE;AAC7D,SAAI,QAAS,YAAW,MAAM;AAC9B,SAAI,YAAa,YAAW,UAAU;AACtC,SAAI,cAAe,YAAW,aAAa;AAC3C,mBAAc,IAAI,mBAAmB,WAAW;;;AAKlD,OAAI,WAAW,SAAS,GAAG;IAC1B,MAAM,kBAAkB,WAAW,QAAQ,CAAC,MAAM,CAAC;IACnD,MAAM,QAAQ,eAAe,IAAI,gBAAgB,IAAI,EAAE;AAEvD,eADe,MAAM,qBAAqB,iBAAiB,MAAM,CAC/C;SAElB,MAAK,MAAM,CAAC,KAAK,cAAc,gBAAgB;IAC9C,MAAM,SAAS,MAAM,qBAAqB,KAAK,UAAU;AACzD,gBAAY,OAAO;;AAKrB,QAAK,MAAM,iBAAiB,YAAY;IACvC,MAAM,cAAc,cAAc,IAAI,cAAc,IAAI,EAAE;IAC1D,MAAM,mBAAmB,WAAW,SAAS,KAAK,kBAAkB;AACpE,UAAM,0BAA0B;KAC/B,mBAAmB;KACnB,KACC,YAAY,QAAQ,mBAAoB,MAA6B,KAAA,MAAc;KACpF,SACC,YAAY,YACX,mBAAoB,UAAiC,KAAA,MACtD;KACD,WACC,YAAY,eACX,mBAAoB,YAAmC,KAAA,MACxD;KACD,kBAAkB,kBAAkB,IAAI,cAAc,IAAI;KAC1D,CAAC;;AAIH,gBAAa,SAAS,WAAW;AAEjC,UAAO,EAAE,KAAK;IAAE;IAAU,UAAW,MAAoB;IAAQ,CAAC;WAC1D,KAAK;GACb,MAAM,WAAoC,EAAE,OAAO,yBAAyB;AAC5E,OAAI,QAAQ,IAAI,yBAAyB,IACxC,UAAS,SAAU,IAAc;AAElC,UAAO,EAAE,KAAK,UAAU,IAAI;;GAE5B;AAGF,KAAI,KAAK,qBAAqB,OAAO,MAAM;EAC1C,MAAM,SAAS,MAAM,oBAAoB,GAAG,0BAA0B;AACtE,MAAI,kBAAkB,SAAU,QAAO;EAIvC,MAAM,WAAW,8BAHD,OAGuC;AACvD,MAAI,aAAa,KAEhB,QAAO,EAAE,KAAK;GAAE,UAAU;GAAG,SAAS;GAAG,CAAC;EAG3C,MAAM,QAAQ,UAAU;AACxB,MAAI;GACH,MAAM,oBAAoB,SAAS;GACnC,MAAM,SAAS,SAAS;GACxB,MAAM,kBAAkB,gBAAgB,SAAS,QAAQ;GAEzD,MAAM,WAAW,MAAM,eAAe;IACrC;IACA;IACA,SAAS,SAAS;IAClB,WAAW;IACX,SAAS;IACT,UAAU,SAAS;IACnB,CAAC;AAEF,SAAM,0BAA0B;IAC/B;IACA;IACA,KAAK,SAAS;IACd,SAAS,SAAS;IAClB,WAAW,SAAS;IACpB,kBAAkB,SAAS;IAC3B,CAAC;AAGF,gBAAa,SAAS,CAAC,kBAAkB,EAAE,OAAO;AAElD,UAAO,EAAE,KAAK;IAAE,UAAU,WAAW,IAAI;IAAG,SAAS;IAAG,CAAC;WACjD,KAAK;GACb,MAAM,WAAoC,EAAE,OAAO,yBAAyB;AAC5E,OAAI,QAAQ,IAAI,yBAAyB,IACxC,UAAS,SAAU,IAAc;AAElC,UAAO,EAAE,KAAK,UAAU,IAAI;;GAE5B;AAEF,QAAO;;;;;;;;;ACxaR,SAAS,sBAAsB,KAIV;AACpB,QAAO,CAAC,IAAI,cAAc,IAAI,YAAY,IAAI,KAAK;;AAGpD,SAAS,4BAEP,MAAgB;AACjB,QAAO,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM;EAC/B,MAAM,CAAC,OAAO,SAAS,sBAAsB,EAAE;EAC/C,MAAM,CAAC,OAAO,SAAS,sBAAsB,EAAE;AAC/C,MAAI,UAAU,MAAO,QAAO,MAAM,cAAc,MAAM;AACtD,SAAO,MAAM,cAAc,MAAM;GAChC;;;;;;AAOH,SAAgB,YAAY,UAA6B;CACxD,MAAM,MAAM,IAAI,MAAM;CAEtB,MAAM,qBAAqB,UAAmD;AAC7E,MAAI,OAAO,UAAU,YAAY,CAAC,MAAM,MAAM,CAAE,QAAO;AACvD,MAAI;AACH,UAAO,KAAK,MAAM,MAAM;UACjB;AACP,UAAO;;;AAIT,KAAI,IAAI,eAAe,MAAM;EAC5B,MAAM,QAAQ,UAAU;EAExB,MAAM,aAAa,4BADN,oBAAoB,MAAM,GAAG,CAEpC,QACH,QAAQ,IAAI,WAAW,aAAa,IAAI,WAAW,aAAa,IAAI,WAAW,SAChF,CACD,CAAC,KAAK,SAAS;GACf,MAAM,IAAI;GACV,OAAO,IAAI;GACX,QAAQ,IAAI;GACZ,SAAS,IAAI;GACb,UAAU,IAAI;GACd,OAAO,IAAI;GACX,EAAE;AACH,SAAO,EAAE,KAAK;GACb,GAAG,MAAM,OAAO;GAChB,YAAY,QAAQ;GACpB,kBAAkB;GAClB,CAAC;GACD;AAEF,KAAI,IAAI,iBAAiB,MAAM;AAC9B,SAAO,EAAE,KAAK,EACb,SAAS,WACT,CAAC;GACD;AAEF,KAAI,IAAI,eAAe,MAAM;EAC5B,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,gBAAgB,EAAE,IAAI,MAAM,UAAU,IAAI;GAChD,MAAM,mBAAmB,gBACtB,MAAM,GAAG,QACT;;;;;;;gBAQA,GACA,MAAM,GAAG,QACT;;;;gBAKA;GACH,MAAM,eAAe,MAAM,GACzB,QACA;;;;;uDAMA,CACA,KAAK;GACP,MAAM,eAAe,MAAM,GACzB,QACA;;;;yBAKA,CACA,KAAK;GACP,IAAI,iBAAmD;GACvD,IAAI,iBAAiD;AACrD,OAAI,eAAe;AAClB,qBAAiB,MAAM,GACrB,QACA;;;;;;;;sCASA,CACA,IAAI,cAAc;AACpB,qBAAiB,MAAM,GACrB,QACA;;;;;;mCAOA,CACA,IAAI,cAAc;;GAKrB,MAAM,eAFL,gBAAgB,iBAAiB,IAAI,cAAc,GAAG,iBAAiB,KAAK,EAE1C,KAAK,SAAS;IAChD,IAAI,OAAO,IAAI,MAAM,EAAE;IACvB,YAAY,IAAI,cAAc,OAAO,OAAO,OAAO,IAAI,WAAW;IAClE,OAAO,OAAO,IAAI,SAAS,OAAO;IAClC,aAAa,OAAO,IAAI,eAAe,EAAE;IACzC,gBAAgB,OAAO,IAAI,kBAAkB,EAAE;IAC/C,cAAc,OAAO,IAAI,gBAAgB,EAAE;IAC3C,YAAY,OAAO,IAAI,cAAc,GAAG;IACxC,eAAe,kBAAkB,IAAI,cAAc;IACnD,EAAE;AAEH,UAAO,EAAE,KAAK;IACb,SAAS;IACT,QAAQ,gBAAgB,iBAAiB;IACzC,QAAQ,gBAAgB,iBAAiB;IACzC,eAAe;IACf,eAAe;IACf,iBAAiB;IACjB,iBAAiB;IACjB,cAAc;IACd,CAAC;;GAEF;AAEF,QAAO;;;;;;;AChFR,IAAM,2BAA2B;AACjC,IAAM,wBAAwB;AAC9B,IAAM,iCAAiC;AACvC,IAAM,6BAA6B;AAInC,SAAS,8BAA8B,SAAS,2BAA2B,EAAE;CAC5E,MAAM,SAAS,OAAO;CACtB,MAAM,cAAc,OAAO,MAAM;CACjC,MAAM,SAAS,QAAQ,OAAO,mBAAmB;CACjD,MAAM,YAAY,OAAO,SAAS;CAClC,MAAM,iBAAiB,QAAQ,OAAO,2BAA2B;CACjE,IAAI,YAAuC;AAC3C,KAAI,CAAC,OAAQ,aAAY;UAChB,CAAC,aAAa,CAAC,eAAgB,aAAY;AACpD,QAAO;EACN;EACA,iBAAiB,OAAO,sBAAsB;EAC9C;EACA,cAAc;EACd,kBAAkB;EAClB,YAAY;EACZ;;AAGF,SAAS,0BAA0B,SAAS,2BAA2B,EAAY;CAClF,MAAM,YAAY,OAAO,OAAO,iBAAiB,OAAO,CACtD,MAAM,CACN,aAAa;AACf,KAAI,aAAa,cAAc,UAAU,cAAc,UACtD,QAAO,eACN,EAAE,EACF,OAAO,OAAO,iBAAiB,GAAG,CAChC,MAAM,IAAI,CACV,KAAK,SAAS,KAAK,MAAM,CAAC,CAC1B,OAAO,QAAQ,CACjB;AAEF,KAAI,OAAO,YAAY,OAAO,aAAa,UAC1C,QAAO,CAAC,GAAG,OAAO,SAAS,GAAG,OAAO,WAAW;CAEjD,MAAM,YAAY,OAAO,OAAO,mBAAmB,CAAC,CAClD,SAAS,YAAY,WAAW,EAAE,CAAC,CACnC,QAAQ,UAAU,CAAC,MAAM,SAAS,CAClC,KAAK,UAAU,MAAM,QAAQ,CAC7B,QAAQ,YAAY,WAAW,YAAY,eAAe,YAAY,MAAM,CAC5E,KAAK,YAAY,GAAG,QAAQ,GAAG,OAAO,WAAW;AACnD,QAAO,CAAC,GAAG,IAAI,IAAI,UAAU,CAAC;;AAG/B,SAAS,6BACR,gBACA,QACgB;CAChB,MAAM,WAAW,OAAO,kBAAkB,GAAG,CAAC,MAAM;AACpD,KAAI,SAAU,QAAO;AACrB,QAAO,OAAO;;AAGf,SAAS,oBAAoB,OAA+B;CAC3D,MAAM,WAAW,OAAO,OAAO,SAAS,GAAG,CAAC;AAC5C,KAAI,CAAC,OAAO,UAAU,SAAS,IAAI,WAAW,EAAG,QAAO;AACxD,QAAO;;AAGR,SAAS,0BAEP,MAAgB;AACjB,QAAO,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,MAAM;EAC/B,MAAM,QAAQ,EAAE,cAAc,EAAE;EAChC,MAAM,QAAQ,EAAE,cAAc,EAAE;AAChC,MAAI,UAAU,MAAO,QAAO,MAAM,cAAc,MAAM;AACtD,SAAO,EAAE,KAAK,cAAc,EAAE,KAAK;GAClC;;AAGH,SAAS,yBACR,MACA,iBACiC;AACjC,QAAO,0BACN,KAAK,QAAQ,QAAQ;EAAC;EAAW;EAAW;EAAS,CAAC,SAAS,OAAO,IAAI,UAAU,GAAG,CAAC,CAAC,CACzF,CAAC,KAAK,SAAS;EACf,MAAM,IAAI;EACV,OAAO,IAAI;EACX,QAAQ,IAAI;EACZ,UAAU,IAAI;EACd,GAAI,kBACD;GACA,SAAS,IAAI;GACb,OAAO,IAAI;GACX,UAAU,IAAI;GACd,GACA,EAAE;EACL,EAAE;;AAGJ,SAAS,+BACR,aACA,iBAC2B;AAC3B,KAAI,mBAAmB,CAAC,YAAY,gBACnC,QAAO;CAER,MAAM,UACL,YAAY,UAAU,YACnB,uCACA,YAAY,UAAU,WACrB,mCACA,YAAY,UAAU,aACrB,+CACA,YAAY;AAClB,QAAO;EACN,GAAG;EACH;EACA,iBAAiB;GAChB,GAAG,YAAY;GACf,SAAS;GACT,OAAO;GACP;EACD;;AAGF,SAAS,cAAkC;AAC1C,QAAO,QAAQ,IAAI,kBAAkB,MAAM,IAAI,KAAA;;AAGhD,SAAS,SAAS,MAAc,UAA0B;CACzD,MAAM,QAAQ,OAAO,SAAS,QAAQ,IAAI,SAAS,IAAI,GAAG;AAC1D,QAAO,OAAO,SAAS,MAAM,GAAG,QAAQ;;AAGzC,IAAM,sBAAsB,SAAS,+BAA+B,QAAU;AAC9E,IAAM,eAAe,SAAS,wBAAwB,IAAK;AAE3D,eAAe,wBAAwB,SAAkB,UAA0C;CAClG,MAAM,gBAAgB,OAAO,SAAS,QAAQ,QAAQ,IAAI,iBAAiB,IAAI,IAAI,GAAG;AACtF,KAAI,OAAO,SAAS,cAAc,IAAI,gBAAgB,SACrD,QAAO;CAER,MAAM,SAAS,QAAQ;AACvB,KAAI,CAAC,OAAQ,QAAO,OAAO,MAAM,EAAE;CACnC,MAAM,SAAS,OAAO,WAAW;CACjC,MAAM,SAAuB,EAAE;CAC/B,IAAI,QAAQ;AACZ,KAAI;AACH,SAAO,MAAM;GACZ,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,MAAM;AAC3C,OAAI,KAAM;AACV,OAAI,CAAC,MAAO;AACZ,YAAS,MAAM;AACf,OAAI,QAAQ,UAAU;AACrB,UAAM,OAAO,QAAQ;AACrB,WAAO;;AAER,UAAO,KAAK,MAAM;;WAEV;AACT,SAAO,aAAa;;AAErB,QAAO,OAAO,OAAO,OAAO,KAAK,UAAU,OAAO,KAAK,MAAM,CAAC,CAAC;;AAGhE,IAAM,sBACL;AAGD,SAAS,cAAc,KAAqB;CAC3C,MAAM,SAAS,IAAI,IAAI,IAAI;AAC3B,QAAO,OAAO,SAAS,GAAG,OAAO,WAAW,OAAO,WAAW,OAAO;;AAGtE,SAAS,oBAAoB,QAAgB,eAAe,OAA+B;AAC1F,KAAI,gBAAgB,QAAQ,IAAI,kCAAkC,IACjE,QAAO;EAAE,OAAO;EAAgB;EAAQ;AAEzC,QAAO,EAAE,OAAO,gBAAgB;;AAGjC,SAAS,qBACR,OACA,SACA,MACoD;CACpD,MAAM,YAAY,QAAQ,OAAO,oBAAoB,IAAI,IAAI,MAAM;CACnE,MAAM,YAAY,QAAQ,OAAO,uBAAuB,IAAI;CAC5D,MAAM,YAAY,QAAQ,OAAO,uBAAuB,IAAI;CAC5D,MAAM,QAAQ,QAAQ,OAAO,mBAAmB,IAAI;AACpD,KAAI,CAAC,YAAY,CAAC,aAAa,CAAC,aAAa,CAAC,MAC7C,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAmB;EAAU;CAG1D,MAAM,UAAU,MAAM,GACpB,QACA,yFACA,CACA,IAAI,SAAS;AACf,KAAI,CAAC,QACJ,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAgB;EAAU;CAGvD,MAAM,oBAAoB,OAAO,QAAQ,sBAAsB,GAAG,CAAC,MAAM;CACzE,MAAM,YAAY,OAAO,QAAQ,cAAc,GAAG,CAAC,MAAM;AACzD,KAAI,CAAC,qBAAqB,CAAC,UAC1B,QAAO;EAAE,IAAI;EAAO,QAAQ;EAA0B;EAAU;AAEjE,KAAI,qBAAqB,UAAU,KAAK,kBACvC,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAwB;EAAU;CAG/D,IAAI,QAAQ;AACZ,KAAI;AACH,UAAQ,gBAAgB;GACvB,QAAQ,QAAQ;GAChB,eAAe,cAAc,QAAQ,IAAI;GACzC,WAAW;GACX;GACA;GACA;GACA;GACA;GACA,CAAC;SACK;AACP,SAAO;GAAE,IAAI;GAAO,QAAQ;GAAgC;GAAU;;AAGvE,KAAI,CAAC,MACJ,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAqB;EAAU;CAG5D,MAAM,6BAAY,IAAI,MAAM,EAAC,aAAa;AAC1C,KAAI,CAAC,YAAY,MAAM,IAAI,UAAU,OAAO,UAAU,CACrD,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAgB;EAAU;CAGvD,MAAM,0BAAS,IAAI,KAAK,KAAK,KAAK,GAAG,wBAAwB,IAAI,IAAK,EAAC,aAAa;AACpF,eAAc,MAAM,IAAI,OAAO;AAC/B,QAAO;EAAE,IAAI;EAAM,QAAQ;EAAM;EAAU;;AAG5C,eAAe,+BACd,OACA,SACA,MAC6D;CAC7D,MAAM,WAAW,QAAQ,OAAO,4BAA4B,IAAI,IAAI,MAAM;CAC1E,MAAM,YAAY,QAAQ,OAAO,oBAAoB,IAAI,IAAI,MAAM;CACnE,MAAM,YAAY,QAAQ,OAAO,uBAAuB,IAAI;CAC5D,MAAM,YAAY,QAAQ,OAAO,uBAAuB,IAAI;CAC5D,MAAM,QAAQ,QAAQ,OAAO,mBAAmB,IAAI;AACpD,KAAI,CAAC,WAAW,CAAC,YAAY,CAAC,aAAa,CAAC,aAAa,CAAC,MACzD,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAmC;EAAU;CAG1E,MAAM,SAAS,2BAA2B;AAC1C,KAAI,CAAC,OAAO,sBAAsB,CAAC,OAAO,2BACzC,QAAO;EAAE,IAAI;EAAO,QAAQ;EAA8C;EAAU;CAGrF,MAAM,CAAC,iBAAiB,qBAAqB,MAAM,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;CAClF,IAAI;AACJ,KAAI;EACH,MAAM,CAAC,QAAQ,WAAW,MAAM,YAC/B,OACA,GAAG,aAAa,OAAO,mBAAmB,CAAC,6BAA6B,mBAAmB,QAAQ,IACnG;GACC,SAAS,EAAE,+BAA+B,OAAO,4BAA4B;GAC7E,UAAU,KAAK,IAAI,GAAG,OAAO,wBAAwB;GACrD,CACD;AACD,MAAI,WAAW,OAAO,CAAC,QACtB,QAAO;GAAE,IAAI;GAAO,QAAQ;GAAiC;GAAU;AAExE,iBAAe;SACR;AACP,SAAO;GAAE,IAAI;GAAO,QAAQ;GAAiC;GAAU;;CAGxE,MAAM,QAAQ,aAAa;CAC3B,MAAM,mBAAmB,aAAa;AACtC,KAAI,CAAC,SAAS,CAAC,iBACd,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAmC;EAAU;AAE1E,KAAI,MAAM,WAAY,QAAO;EAAE,IAAI;EAAO,QAAQ;EAA2B;EAAU;AACvF,KAAI,OAAO,iBAAiB,UAAU,KAAK,OAAO,MAAM,iBAAiB,CACxE,QAAO;EAAE,IAAI;EAAO,QAAQ;EAA8C;EAAU;AAErF,KAAI,OAAO,iBAAiB,SAAS,KAAK,OAAO,MAAM,SAAS,CAC/D,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAkC;EAAU;AAEzE,KAAI,OAAO,iBAAiB,QAAQ,KAAK,EACxC,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAmC;EAAU;AAE1E,KAAI,MAAM,qBAAqB,SAC9B,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAmC;EAAU;AAE1E,KAAI,MAAM,mBAAmB,cAC5B,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAiC;EAAU;AAExE,KAAI,IAAI,KAAK,MAAM,WAAW,oBAAI,IAAI,MAAM,CAC3C,QAAO;EAAE,IAAI;EAAO,QAAQ;EAA2B;EAAU;CAGlE,IAAI,QAAQ;AACZ,KAAI;AACH,UAAQ,gBAAgB;GACvB,QAAQ,QAAQ;GAChB,eAAe,cAAc,QAAQ,IAAI;GACzC,WAAW;GACX;GACA;GACA;GACA,WAAW,OAAO,iBAAiB,WAAW;GAC9C;GACA,CAAC;SACK;AACP,SAAO;GAAE,IAAI;GAAO,QAAQ;GAAgD;GAAU;;AAEvF,KAAI,CAAC,MACJ,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAqC;EAAU;CAG5E,MAAM,6BAAY,IAAI,MAAM,EAAC,aAAa;AAC1C,KAAI,CAAC,YAAY,MAAM,IAAI,UAAU,OAAO,UAAU,CACrD,QAAO;EAAE,IAAI;EAAO,QAAQ;EAAgB;EAAU;CAEvD,MAAM,0BAAS,IAAI,KAAK,KAAK,KAAK,GAAG,wBAAwB,IAAI,IAAK,EAAC,aAAa;AACpF,eAAc,MAAM,IAAI,OAAO;AAC/B,QAAO;EAAE,IAAI;EAAM,QAAQ;EAAM;EAAU;;AAG5C,SAAS,cAAc,OAA0B;AAChD,KAAI,SAAS,KAAM,QAAO,EAAE;AAC5B,KAAI,OAAO,UAAU,SACpB,KAAI;EACH,MAAM,SAAS,KAAK,MAAM,MAAM;AAChC,MAAI,CAAC,MAAM,QAAQ,OAAO,CAAE,QAAO,EAAE;AACrC,SAAO,OAAO,KAAK,UAAU,OAAO,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,QAAQ;SACjE;AACP,SAAO,EAAE;;AAGX,KAAI,CAAC,MAAM,QAAQ,MAAM,CAAE,QAAO,EAAE;AACpC,QAAO,MAAM,KAAK,UAAU,OAAO,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,QAAQ;;AAGxE,SAAS,uBACR,OACA,cAC2C;CAC3C,MAAM,eAAe,2BAA2B;CAChD,MAAM,MAAM,MAAM,GAChB,QACA,uGACA,CACA,IAAI,aAAa;AAGnB,KAAI,CAAC,IACJ,QAAO;EACN,SAAS,aAAa;EACtB,SAAS,aAAa;EACtB;AAGF,KAAI,EADgB,IAAI,yBAAyB,QAAQ,IAAI,yBAAyB,MAErF,QAAO;EACN,SAAS,aAAa;EACtB,SAAS,aAAa;EACtB;AAEF,QAAO;EACN,SAAS,cAAc,IAAI,sBAAsB;EACjD,SAAS,cAAc,IAAI,sBAAsB;EACjD;;AAGF,SAAS,oBACR,KACA,WAC0B;AAC1B,QAAO;EACN,SAAS,aAAa,IAAI,sBAAuC;EACjE,SAAS,aAAa,IAAI,sBAAuC;EACjE,mBACC,WAAW,WAAW,aAAa,IAAI,sBAAuC;EAC/E,mBACC,WAAW,WAAW,aAAa,IAAI,sBAAuC;EAC/E,iBAAiB,IAAI,yBAAyB,QAAQ,IAAI,yBAAyB;EACnF;;AAGF,SAAS,uBAAuB,OAA0B;CACzD,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;AAMvC,KALiB,EACf,OAAO,EAAE,UAAU,OAAO,OAAO,UAAU,CAAC,CAC5C,KAAK,OAAO,OAAO,CACnB,MAAM,GAAG,OAAO,OAAO,UAAU,MAAM,QAAQ,CAAC,CAChD,KAAK,CACO;CACd,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,GAAE,OAAO,OAAO,OAAO,CACrB,OAAO;EACP,UAAU,MAAM;EAChB,cAAc,MAAM;EACpB,UAAU;EACV,QAAQ;EACR,sBAAsB;EACtB,YAAY;EACZ,YAAY;EACZ,CAAC,CACD,KAAK;;AAGR,SAAS,2BAA2B,OAAoB,SAAgC;CACvF,MAAM,OAAO,MAAM,GACjB,QAAQ,wDAAwD,CAChE,KAAK;AACP,MAAK,MAAM,OAAO,KAEjB,KADkB,aAAa,IAAI,eAAe,CACpC,SAAS,QAAQ,CAAE,QAAO,OAAO,IAAI,kBAAkB,GAAG,CAAC,MAAM,IAAI;AAEpF,QAAO;;AAGR,SAAS,wBAAwB,OAAoB,gBAAgC;CACpF,MAAM,WAAW,OAAO,kBAAkB,GAAG,CAAC,MAAM;AACpD,KAAI,CAAC,YAAY,aAAa,aAAa,aAAa,MAAM,SAAU,QAAO;CAC/E,MAAM,sBAAsB,YAAY,MAAM;CAC9C,MAAM,SAAS,MAAM,GACnB,QACA;;;;;;;;;;;;;;;;;;;;;;;;;;WA2BA,CACA,IACA,MAAM,SACN,MAAM,kBACN,qBACA,UACA,MAAM,SACN,gCACA,2BACA;AACF,QAAO,OAAO,OAAO,WAAW,EAAE;;AAGnC,SAAS,sBAAsB,OAAoB,cAA+B;CACjF,MAAM,MAAM,MAAM,GAChB,QAAQ,8EAA8E,CACtF,IAAI,aAAa;AACnB,QAAO,QAAQ,KAAK,oBAAoB;;AAGzC,SAAS,eAAe,IAAqE;AAC5F,KAAI,CAAC,GAAG,gBAAgB,CAAC,OAAO,GAAG,aAAa,CAAC,MAAM,CAAE,QAAO;AAChE,KAAI;EACH,MAAM,SAAS,KAAK,MAAM,GAAG,aAAa;AAC1C,MAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,CAAE,QAAO;AAC3E,SAAO;SACA;AACP,SAAO;;;AAIT,SAAS,wBACR,aACA,UAC0B;AAC1B,KAAI,SAAU,QAAO;CACrB,MAAM,aAAa,MAAM,QAAQ,YAAY,mBAAmB,GAC7D,YAAY,mBAAmB,KAAK,SAAS;AAC7C,MAAI,CAAC,QAAQ,OAAO,SAAS,SAAU,QAAO;EAC9C,MAAM,SAAS;AACf,SAAO;GACN,WAAW,OAAO;GAClB,cAAc,OAAO,gBAAgB;GACrC,QAAQ,MAAM,QAAQ,OAAO,OAAO,GAAG,OAAO,SAAS,EAAE;GACzD,cAAc,OAAO,gBAAgB;GACrC,YAAY,OAAO,cAAc;GACjC,OAAO,QAAQ,OAAO,MAAM;GAC5B,sBAAsB,QAAQ,OAAO,qBAAqB;GAC1D,2BAA2B,QAAQ,OAAO,0BAA0B;GACpE,gCAAgC,OAAO,kCAAkC;GACzE,gCAAgC,OAAO,kCAAkC;GACzE,aAAa;GACb,WAAW,EAAE;GACb;GACA,GACD,EAAE;AACL,QAAO;EACN,GAAG;EACH,oBAAoB;EACpB;;AAGF,eAAe,qBACd,OACA,OAIC;CACD,MAAM,SAAS,2BAA2B;AAC1C,KACC,CAAC,OAAO,eACR,CAAC,OAAO,sBACR,OAAO,sBAAsB,WAAW,EAExC,QAAO;EACN,IAAI;EACJ,QAAQ;EACR,OAAO;EACP,QAAQ;EACR;CAGF,MAAM,SADa,MAAM,uBAAuB,OAAO,OAAO,EACrC,MACvB,SACA,OAAO,KAAK,aAAa,GAAG,CAAC,MAAM,KAAK,MAAM,gBAC9C,OAAO,KAAK,eAAe,GAAG,CAAC,MAAM,KAAK,MAAM,YACjD;AACD,KAAI,CAAC,MACJ,QAAO;EACN,IAAI;EACJ,QAAQ;EACR,OAAO;EACP,QAAQ;EACR;CAEF,MAAM,kBAAkB,OAAO,MAAM,eAAe,GAAG,CAAC,MAAM;CAC9D,MAAM,gBAAgB,OAAO,MAAM,cAAc,GAAG,CAAC,MAAM;CAC3D,MAAM,WAAW,OAAO,MAAM,gBAAgB,GAAG,CAAC,MAAM,IAAI;CAC5D,MAAM,gBAAgB,MAAM,QAAQ,MAAM,UAAU,GACjD,MAAM,UAAU,QAAQ,UAA2B,OAAO,UAAU,SAAS,GAC7E,EAAE;AACL,KAAI,CAAC,cACJ,QAAO;EACN,IAAI;EACJ,QAAQ;EACR,OAAO;EACP,QACC;EACD;CAGF,MAAM,WAAW,MAAM,QAAQ,MAAM,OAAO,GACzC,MAAM,OAAO,KAAK,UAAU,OAAO,SAAS,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,QAAQ,GACvE,EAAE;AACL,KAAI,SAAS,WAAW,EACvB,QAAO;EACN,IAAI;EACJ,QAAQ;EACR,OAAO;EACP,QACC,SAAS,SAAS,IACf,gHACA;EACJ;CAEF,MAAM,UAAU,SAAS;CACzB,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;CACvC,MAAM,WAAW,EACf,OAAO;EACP,gBAAgB,OAAO,UAAU;EACjC,oBAAoB,OAAO,UAAU;EACrC,YAAY,OAAO,UAAU;EAC7B,gBAAgB,OAAO,UAAU;EACjC,CAAC,CACD,KAAK,OAAO,UAAU,CACtB,MAAM,GAAG,OAAO,UAAU,gBAAgB,MAAM,aAAa,CAAC,CAC9D,KAAK;CACP,MAAM,sBAAsB,OAAO,UAAU,sBAAsB,GAAG,CAAC,MAAM;AAC7E,KAAI,YAAY,uBAAuB,wBAAwB,gBAC9D,QAAO;EACN,IAAI;EACJ,QAAQ;EACR,OAAO;EACP,QACC;EACD;CAEF,MAAM,2BAA2B;AAChC,MAAI;GACH,MAAM,MAAM,KAAK,MAAM,OAAO,UAAU,kBAAkB,KAAK,CAAC;AAChE,UAAO,MAAM,QAAQ,IAAI,GACtB,IAAI,QAAQ,UAA2B,OAAO,UAAU,SAAS,GACjE,EAAE;UACE;AACP,UAAO,EAAE;;KAEP;CACJ,MAAM,gBAAgB,KAAK,UAAU,eAAe,mBAAmB,cAAc,CAAC;AACtF,OAAM,oCAAoC,OAAO,QAAQ;EACxD;EACA,mBAAmB,MAAM;EACzB,CAAC;CACF,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AAwCpC,QAvCe,MAAM,GAAG,kBAAkB;AACzC,MAAI,CAAC,UAAU;AACd,KAAE,OAAO,OAAO,UAAU,CACxB,OAAO;IACP,gBAAgB,MAAM;IACtB,MAAM;IACN,oBAAoB,mBAAmB;IACvC,YAAY;IACZ,gBAAgB;IAChB,YAAY;IACZ,cAAc;IACd,CAAC,CACD,KAAK;AACP,UAAO;IACN,IAAI;IACJ,gBAAgB,MAAM;IACtB,SAAS;IACT,SAAS;IACT,MAAM;IACN;;AAEF,IAAE,OAAO,OAAO,UAAU,CACxB,IAAI;GACJ,MAAM;GACN,oBAAoB,mBAAmB,SAAS,sBAAsB;GACtE,YAAY,iBAAiB,SAAS,cAAc;GACpD,gBAAgB;GAChB,cAAc;GACd,CAAC,CACD,MAAM,GAAG,OAAO,UAAU,gBAAgB,MAAM,aAAa,CAAC,CAC9D,KAAK;AACP,SAAO;GACN,IAAI;GACJ,gBAAgB,MAAM;GACtB,SAAS;GACT,SAAS;GACT,MAAM;GACN;GACA,EAAE;;AAIL,SAAS,iBACR,OACA,cACA,KACgD;CAChD,MAAM,UAAU,uBAAuB,OAAO,aAAa;CAC3D,MAAM,eAAe,sBAAsB,OAAO,aAAa;CAC/D,MAAM,UAA2B,EAAE;CACnC,IAAI,UAAU;AACd,MAAK,MAAM,MAAM,KAAK;AACrB,MAAI,GAAG,gBAAgB,eAAe;AACrC,WAAQ,KAAK,GAAG;AAChB;;EAED,MAAM,UAAU,eAAe,GAAG;AAClC,MAAI,CAAC,gBAAgB,CAAC,sBAAsB,QAAQ,EAAE;AACrD;AACA;;AAGD,MAAI,CAAC,4BADW,WAAW,OAAO,QAAQ,YAAY,WAAW,QAAQ,UAAU,MACzC,QAAQ,EAAE;AACnD;AACA;;AAED,UAAQ,KAAK,GAAG;;AAEjB,QAAO;EAAE;EAAS;EAAS;;;;;;;AAY5B,SAAS,WACR,OACA,KACA,UAC0B;AAC1B,QAAO;EACN,gBAAgB,IAAI;EACpB,MAAM,IAAI;EACV,aAAa,WAAW,IAAI,qBAAqB;EACjD,QAAQ,QAAQ,IAAI,mBAAmB;EACvC,WAAW,WAAW,aAAa,IAAI,eAAgC,GAAG,EAAE;EAC5E,cAAc,IAAI;EAClB,cAAc,IAAI;EAClB,YAAY,WAAW,IAAI,aAAa;EACxC,WAAW,QAAQ,IAAI,WAAW;EAClC,qBAAqB,QAAQ,IAAI,oBAAoB;EACrD,UAAU,IAAI,YAAY;EAC1B,oBAAoB,IAAI,sBAAsB;EAC9C,eAAe,EACd,GAAG,oBAAoB,KAAK,uBAAuB,OAAO,OAAO,IAAI,kBAAkB,GAAG,CAAC,CAAC,EAC5F;EACD;;AAOF,SAAS,YAAY,OAAgB,UAAU,0BAAmC;CACjF,MAAM,MAAM,OAAO,SAAS,GAAG,CAAC,MAAM;AACtC,KAAI,CAAC,IAAK,QAAO;CACjB,MAAM,aAAa,IAAI,QAAQ,KAAK,SAAS;CAC7C,MAAM,YAAY,2BAA2B,KAAK,IAAI;CACtD,MAAM,KAAK,IAAI,KAAK,YAAY,aAAa,GAAG,WAAW,QAAQ;AACnE,KAAI,OAAO,MAAM,GAAG,SAAS,CAAC,CAAE,QAAO;CACvC,MAAM,QAAQ,KAAK,KAAK,GAAG,GAAG,SAAS,IAAI;AAC3C,QAAO,QAAQ,KAAK,QAAQ;;AAG7B,SAAS,WAAW,MAAwD;CAC3E,MAAM,aAAa,KAAK;CACxB,MAAM,aAAa,KAAK;CACxB,MAAM,WAAW,QAAQ,KAAK,UAAU;CAExC,MAAM,YAAY,YAAY,WAAW;CACzC,MAAM,YAAY,YAAY,WAAW;CAEzC,IAAI;AACJ,KAAI,YAAY,EAAE,aAAa,WAAY,aAAY;UAC9C,SAAU,aAAY;UACtB,aAAa,UAAW,aAAY;UACpC,cAAc,WAAY,aAAY;KAC1C,aAAY;AAKjB,QAAO;EACN,aAJkB,WAAW,UAAU,YAAY,OAAO,aAAa,UAAU;EAKjF,aAJkB,YAAY,OAAO,aAAa,UAAU;EAK5D,YAAY;EACZ,OAAO,aAAa;EACpB,cAAc;EACd,cAAc;EACd;;AAGF,SAAS,cAAc,SAA0C;AAChE,KAAI,QAAQ,GAAI,QAAO;AACvB,KAAI,QAAQ,MAAO,QAAO;AAC1B,QAAO;;AAGR,SAAS,kBAAkB,QAAuD;AACjF,KAAI;EACH,MAAM,MAAM,aAAa,KAAK,QAAQ,OAAO,EAAE,aAAa,EAAE,OAAO;EACrE,MAAM,SAAS,KAAK,MAAM,IAAI;AAC9B,MAAI,OAAO,OAAO,SAAS,YAAY,OAAO,OAAO,SAAS,SAC7D,QAAO;GAAE,MAAM,OAAO;GAAM,MAAM,OAAO;GAAM;SAEzC;AAGR,QAAO;;AAGR,eAAe,SAAS,MAAc,MAAgC;AACrE,QAAO,IAAI,SAAS,YAAY;EAC/B,MAAM,SAAS,IAAI,iBAAiB;GAAE;GAAM;GAAM,CAAC;EACnD,MAAM,QAAQ,OAAgB;AAC7B,UAAO,oBAAoB;AAC3B,UAAO,SAAS;AAChB,WAAQ,GAAG;;AAEZ,SAAO,WAAW,IAAI;AACtB,SAAO,KAAK,iBAAiB,KAAK,KAAK,CAAC;AACxC,SAAO,KAAK,iBAAiB,KAAK,MAAM,CAAC;AACzC,SAAO,KAAK,eAAe,KAAK,MAAM,CAAC;GACtC;;AAGH,IAAM,cAAc;;;;;;;;;;;;;;;;AAqBpB,SAAgB,mBAAmB,UAAwB,OAAiC,EAAE,EAAE;CAC/F,MAAM,MAAM,IAAI,MAAM;CACtB,MAAM,iBAAiB,KAAK,kBAAkB;CAE9C,SAAS,oBAAoB,GAAY,KAAa,eAAwB;AAC7E,MAAI,CAAC,eAAgB,QAAO;EAC5B,MAAM,SAAS,EAAE,IAAI,WAAW,SAAS,EAAE,IAAI,WAAW,UAAU,EAAE,IAAI,WAAW;EACrF,MAAM,SAAS,eAAe,QAAQ,MACrC,GAAG,EAAE,IAAI,OAAO,GAAG,gBAAgB,SAAS,OAAO,GAAG,OACtD,gBACG,SACC,eAAe,YACf,eAAe,gBAChB,SACC,eAAe,2BACf,eAAe,6BACnB;AACD,MAAI,OAAO,QAAS,QAAO;AAC3B,IAAE,OAAO,eAAe,OAAO,OAAO,YAAY,CAAC;AACnD,SAAO,EAAE,KAAK;GAAE,OAAO;GAAgB,eAAe,OAAO;GAAa,EAAE,IAAI;;AAIjF,KAAI,IAAI,eAAe,MAAM;EAC5B,MAAM,QAAQ,UAAU;AACxB,UAAQ,YAAY;GACnB,IAAI,OAAO,qBAAqB,OAAO,EAAE,KAAK,OAAO,MAAM,EAAE,CAAC;GAC9D,IAAI,iBAAiB;GACrB,IAAI,qBAAqB;AACzB,OAAI,CAAC,KAAK,IAAI;AAEb,SAD0B,EAAE,IAAI,OAAO,4BAA4B,IAAI,IAAI,MAAM,EAC3D;AACrB,sBAAiB;KAGjB,MAAM,mBAAmB,oBAAoB,GAAG,EAAE,IAAI,MAAM,MAAM;AAClE,SAAI,iBAAkB,QAAO;WACvB;AACN,sBAAiB;KACjB,MAAM,gBAAgB,oBAAoB,GAAG,EAAE,IAAI,MAAM,MAAM;AAC/D,SAAI,cAAe,QAAO;;AAE3B,WAAO,MAAM,+BAA+B,OAAO,EAAE,KAAK,OAAO,MAAM,EAAE,CAAC;AAC1E,yBAAqB;;AAEtB,OAAI,CAAC,KAAK,IAAI;AAGb,QAAI,mBACH,SAAQ,KACP,8CAA8C,KAAK,OAAO,UAAU,EAAE,IAAI,OAAO,4BAA4B,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,IAAI,OAC1I;IAEF,MAAM,aAAa,qBAAqB,4BAA4B,KAAK;AACzE,YACE,iBAAiB,OAAO,oBAAoB,GAAG,EAAE,IAAI,MAAM,MAAM,KAClE,EAAE,KAAK,oBAAoB,WAAW,EAAE,IAAI;;GAG9C,MAAM,UAAU,oBAAoB,GAAG,KAAK,UAAU,KAAK;AAC3D,OAAI,QAAS,QAAO;AAEpB,OAAI;IACH,MAAM,CAAC,UAAU,eAAe,qBAAqB,MAAM,IAAI,EAC9D,SAAS,aAAa,EACtB,CAAC;IACF,MAAM,YAAY,kBAAkB,MAAM,GAAG;AAC7C,WAAO,EAAE,KAAK;KACb,WAAW;KACX,kBAAkB;KAClB;KACA,YAAY;KACZ,CAAC;WACK;AACP,WAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;;MAE7C;GACH;AAGF,KAAI,IAAI,YAAY,MAAM;EACzB,MAAM,QAAQ,UAAU;EACxB,MAAM,OAAO,qBAAqB,OAAO,EAAE,KAAK,OAAO,MAAM,EAAE,CAAC;AAChE,MAAI,CAAC,KAAK,GACT,QACC,oBAAoB,GAAG,EAAE,IAAI,MAAM,MAAM,IAAI,EAAE,KAAK,oBAAoB,KAAK,OAAO,EAAE,IAAI;EAE5F,MAAM,UAAU,oBAAoB,GAAG,KAAK,UAAU,KAAK;AAC3D,MAAI,QAAS,QAAO;EACpB,MAAM,eAAe,KAAK;AAE1B,MAAI;GACH,MAAM,QAAQ,EAAE,IAAI,MAAM,QAAQ,IAAI;GACtC,MAAM,WAAW,OAAO,SAAS,EAAE,IAAI,MAAM,QAAQ,IAAI,OAAO,GAAG;GACnE,MAAM,gBAAgB,EAAE,IAAI,MAAM,aAAa;GAC/C,MAAM,aACL,iBAAiB,QAAQ,cAAc,MAAM,CAAC,SAAS,IACpD,OAAO,SAAS,eAAe,GAAG,GAClC;GACJ,MAAM,aAAa,EAAE,IAAI,MAAM,cAAc,IAAI;GACjD,MAAM,iBAAiB,EAAE,IAAI,MAAM,kBAAkB,IAAI;GACzD,MAAM,QAAQ,OAAO,SAAS,SAAS,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,IAAK,CAAC,GAAG;GAClF,MAAM,CAAC,iBAAiB,qBAAqB,MAAM,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;GAClF,MAAM,SAAS,0BAA0B,MAAM,IAAI;IAClD;IACA;IACA,UAAU;IACV,YAAY,OAAO,SAAS,WAAW,GAAG,aAAa;IACvD;IACA;IACA,CAAC;AACF,OAAI,OAAO,eACV,QAAO,EAAE,KACR;IACC,OAAO;IACP,GAAG,OAAO;IACV,EACD,IACA;GAEF,MAAM,EAAE,KAAK,YAAY,aAAa;GACtC,MAAM,WAAW,iBAAiB,OAAO,cAAc,IAAI;AAC3D,UAAO,EAAE,KAAK;IACb,gBAAgB;IAChB,YAAY,SAAS;IACrB,aAAa,SAAS;IACtB,iBAAiB,SAAS;IAC1B,uBAAuB,SAAS;IAChC,KAAK,SAAS;IACd,aAAa;IACb,SAAS,SAAS;IAClB,CAAC;UACK;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;;GAE/C;AAGF,KAAI,IAAI,iBAAiB,MAAM;EAC9B,MAAM,QAAQ,UAAU;AACxB,UAAQ,YAAY;GACnB,IAAI,OAAO,qBAAqB,OAAO,EAAE,KAAK,OAAO,MAAM,EAAE,CAAC;GAC9D,IAAI,iBAAiB;GACrB,IAAI,qBAAqB;AACzB,OAAI,CAAC,KAAK,IAAI;AAEb,SAD0B,EAAE,IAAI,OAAO,4BAA4B,IAAI,IAAI,MAAM,EAC3D;AACrB,sBAAiB;KAGjB,MAAM,mBAAmB,oBAAoB,GAAG,EAAE,IAAI,MAAM,MAAM;AAClE,SAAI,iBAAkB,QAAO;WACvB;AACN,sBAAiB;KACjB,MAAM,gBAAgB,oBAAoB,GAAG,EAAE,IAAI,MAAM,MAAM;AAC/D,SAAI,cAAe,QAAO;;AAE3B,WAAO,MAAM,+BAA+B,OAAO,EAAE,KAAK,OAAO,MAAM,EAAE,CAAC;AAC1E,yBAAqB;;AAEtB,OAAI,CAAC,KAAK,IAAI;AAGb,QAAI,mBACH,SAAQ,KACP,8CAA8C,KAAK,OAAO,UAAU,EAAE,IAAI,OAAO,4BAA4B,IAAI,IAAI,MAAM,CAAC,QAAQ,EAAE,IAAI,OAC1I;IAEF,MAAM,aAAa,qBAAqB,4BAA4B,KAAK;AACzE,YACE,iBAAiB,OAAO,oBAAoB,GAAG,EAAE,IAAI,MAAM,MAAM,KAClE,EAAE,KAAK,oBAAoB,WAAW,EAAE,IAAI;;GAG9C,MAAM,UAAU,oBAAoB,GAAG,KAAK,UAAU,KAAK;AAC3D,OAAI,QAAS,QAAO;AAEpB,OAAI;IACH,MAAM,gBAAgB,EAAE,IAAI,MAAM,aAAa;IAC/C,MAAM,aACL,iBAAiB,QAAQ,cAAc,MAAM,CAAC,SAAS,IACpD,OAAO,SAAS,eAAe,GAAG,GAClC;IACJ,MAAM,aAAa,EAAE,IAAI,MAAM,cAAc,IAAI;IACjD,MAAM,iBAAiB,EAAE,IAAI,MAAM,kBAAkB,IAAI;IACzD,MAAM,YAAY,EAAE,IAAI,MAAM,aAAa,IAAI;IAC/C,MAAM,WAAW,OAAO,SAAS,EAAE,IAAI,MAAM,QAAQ,IAAI,OAAO,GAAG;IAEnE,MAAM,QAAQ,OAAO,SAAS,SAAS,GAAG,KAAK,IAAI,GAAG,KAAK,IAAI,UAAU,IAAK,CAAC,GAAG;AAElF,QAAI,cAAc,QAAQ,CAAC,OAAO,SAAS,WAAW,CACrD,QAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,EAAE,IAAI;AAEpD,QAAI,CAAC,WACJ,QAAO,EAAE,KAAK,EAAE,OAAO,uBAAuB,EAAE,IAAI;IAGrD,MAAM,SAAS,8BAA8B,MAAM,IAAI;KACtD;KACA;KACA;KACA;KACA;KACA,cAAc,KAAK;KACnB,CAAC;AAEF,WAAO,EAAE,KAAK;KACb,YAAY,OAAO,SAAS;KAC5B,aAAa,OAAO,SAAS;KAC7B,iBAAiB,OAAO,SAAS;KACjC,uBAAuB,OAAO,SAAS;KACvC,OAAO,OAAO;KACd,iBAAiB,OAAO;KACxB,UAAU,OAAO;KACjB,CAAC;YACM,KAAK;IACb,MAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,QAAI,YAAY,yBAAyB,YAAY,oBACpD,QAAO,EAAE,KAAK,EAAE,OAAO,SAAS,EAAE,IAAI;AAEvC,WAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;;MAE7C;GACH;AAGF,KAAI,KAAK,WAAW,OAAO,MAAM;EAChC,MAAM,QAAQ,UAAU;EACxB,MAAM,MAAM,MAAM,wBAAwB,EAAE,IAAI,KAAK,oBAAoB;AACzE,MAAI,OAAO,KACV,QAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,EAAE,IAAI;EAGnD,MAAM,OAAO,qBAAqB,OAAO,EAAE,KAAK,IAAI;AACpD,MAAI,CAAC,KAAK,GACT,QACC,oBAAoB,GAAG,EAAE,IAAI,MAAM,MAAM,IAAI,EAAE,KAAK,oBAAoB,KAAK,OAAO,EAAE,IAAI;EAE5F,MAAM,UAAU,oBAAoB,GAAG,KAAK,UAAU,KAAK;AAC3D,MAAI,QAAS,QAAO;EACpB,MAAM,eAAe,KAAK;EAE1B,IAAI;AACJ,MAAI;GACH,MAAM,SAAS,KAAK,MAAM,IAAI,SAAS,QAAQ,CAAC;AAChD,OAAI,CAAC,UAAU,OAAO,WAAW,YAAY,MAAM,QAAQ,OAAO,CACjE,QAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;AAE9C,UAAO;UACA;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;AAG9C,MAAI,CAAC,MAAM,QAAQ,KAAK,IAAI,CAC3B,QAAO,EAAE,KAAK,EAAE,OAAO,eAAe,EAAE,IAAI;AAE7C,MAAI,KAAK,IAAI,SAAS,aACrB,QAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;EAG9C,MAAM,gBAAgB,sBAAsB,KAAK;AACjD,OAAK,MAAM,MAAM,cAChB,KAAI,GAAG,cAAc,gBAAgB,GAAG,oBAAoB,aAC3D,QAAO,EAAE,KACR;GACC,OAAO;GACP,QAAQ;GACR,OAAO,GAAG;GACV,EACD,IACA;EAGH,MAAM,CAAC,iBAAiB,qBAAqB,MAAM,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;EAElF,MAAM,kBAAkB,iBAAiB,OAAO,cAAc,cAAc;EAC5E,MAAM,SAAS,oBAAoB,MAAM,IAAI,gBAAgB,SAAS,cAAc;AACpF,SAAO,EAAE,KAAK;GACb,GAAG;GACH,SAAS,OAAO,UAAU,gBAAgB;GAC1C,CAAC;GACD;AAEF,QAAO;;;;;;;;;AAUR,SAAgB,WACf,UACA,sBACC;CACD,MAAM,MAAM,IAAI,MAAM;AAGtB,KAAI,IAAI,oBAAoB,OAAO,MAAM;EACxC,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,aAAgB,OAAe,OAAmB;AACvD,QAAI,QAAQ,IAAI,8BAA8B,IAAK,QAAO,IAAI;IAC9D,MAAM,YAAY,KAAK,KAAK;AAC5B,YAAQ,KAAK,yBAAyB,MAAM,QAAQ;AACpD,QAAI;AACH,YAAO,IAAI;cACF;AACT,aAAQ,KAAK,yBAAyB,MAAM,GAAG,KAAK,KAAK,GAAG,UAAU,IAAI;;;GAG5E,MAAM,WAAW,UAAU,EAAE,IAAI,MAAM,qBAAqB,CAAC;GAC7D,MAAM,sBAAsB,UAAU,EAAE,IAAI,MAAM,sBAAsB,CAAC;GACzE,MAAM,UAAU,EAAE,IAAI,MAAM,UAAU,IAAI;GAC1C,MAAM,SAAS,UAAU,mCAAmC,2BAA2B,CAAC;GACxF,MAAM,YAAY,UAAU,2BAA2B,kBAAkB,MAAM,GAAG,CAAC;GAEnF,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;GAEvC,MAAM,YAAY,UAAU,mBAC3B,EACE,OAAO;IACP,WAAW,OAAO,WAAW;IAC7B,aAAa,OAAO,WAAW;IAC/B,CAAC,CACD,KAAK,OAAO,WAAW,CACvB,MAAM,EAAE,CACR,KAAK,CACP;GAED,MAAM,cAAc,UAAU,qBAC7B,EAAE,QAAQ,CAAC,KAAK,OAAO,gBAAgB,CAAC,MAAM,GAAG,OAAO,gBAAgB,IAAI,EAAE,CAAC,CAAC,KAAK,CACrF;GAED,MAAM,eAAe,UAAU,sBAC9B,EAAE,OAAO,EAAE,OAAO,OAAO,EAAE,CAAC,CAAC,KAAK,OAAO,UAAU,CAAC,KAAK,CACzD;GACD,IAAI;AAYJ,OAAI;AACH,qBAAiB,UAAU,wBAC1B,EACE,QAAQ,CACR,KAAK,OAAO,mBAAmB,CAC/B,MAAM,GAAG,OAAO,mBAAmB,IAAI,EAAE,CAAC,CAC1C,KAAK,CACP;WACM;AACP,qBAAiB,KAAA;;GAGlB,MAAM,cAAc,UAAU,qBAC7B,EACE,OAAO,EAAE,cAAc,IAAI,OAAO,UAAU,aAAa,EAAE,CAAC,CAC5D,KAAK,OAAO,UAAU,CACtB,KAAK,CACP;GACD,MAAM,gBAAgB,UAAU,uBAC/B,+BACC,4BAA4B,MAAM,IAAI,EAAE,YAAY,CAAC,UAAU,CAAC,EAChE,SACA,CACD;GAED,MAAM,YAAY,aAAa;GAC/B,MAAM,cAAc,aAAa;GACjC,MAAM,WAAW,aAAa;GAC9B,MAAM,gBAAgB,UAAU,2BAA2B,kBAAkB,MAAM,OAAO,CAAC;GAC3F,MAAM,gBAAgB,gBACnB,MAAM,SAAS,cAAc,MAAM,cAAc,KAAK,GACtD;GACH,MAAM,eAAe,gBAClB,gBACC,qBAAqB,cAAc,KAAK,GAAG,cAAc,SACzD,uBAAuB,cAAc,KAAK,GAAG,cAAc,KAAK,mBACjE;GAEH,IAAI,mBAAmB;AACvB,OAAI,CAAC,OAAO,YACX,oBAAmB;YACT,cAAc,CAAC,YAAY,OAAO,SAAS,GAAG,OAAO,eAAe,GAAG,EACjF,oBAAmB;YACT,CAAC,cACX,oBAAmB;GAGpB,MAAM,gBAAyC;IAC9C,SAAS,OAAO;IAChB,YAAY,OAAO;IACnB,WAAW;KACV,SAAS,OAAO;KAChB,cAAc,OAAO;KACrB,aAAa,OAAO;KACpB,uBACC,UAAU,yBACT,gBAAgB,yBACjB;KACD,aAAc,gBAAgB,eAAiC;KAC/D,kBACC,OAAO,gBAAgB,qBAAqB,WACzC,eAAe,mBACf;KACJ,kBACC,OAAO,gBAAgB,qBAAqB,WACzC,eAAe,mBACf;KACJ,6BACC,OAAO,gBAAgB,gCAAgC,WACpD,eAAe,8BACf;KACJ,4BACC,OAAO,gBAAgB,+BAA+B,WACnD,eAAe,6BACf;KACJ,YAAa,gBAAgB,cAAgC;KAC7D,eAAgB,gBAAgB,iBAAmC;KACnE;IACD,gBAAgB;IAChB,YAAY,OAAO,cAAc,SAAS,EAAE;IAC5C,cAAc,aAAa,gBAAgB;IAC3C,cAAc;IACd,gBAAgB;IAChB,eAAe;IACf,uBACC,OAAO,oBAAoB,SAAS,KAAK,OAAO,oBAAoB,SAAS;IAC9E,gBAAgB;KACf,SAAS,OAAO;KAChB,SAAS,OAAO;KAChB;IACD,UAAU,CAAC;IACX;AAED,OAAI,UAAU;AACb,kBAAc,YAAY,WAAW,aAAa;AAClD,kBAAc,cAAc,WAAW,eAAe;AACtD,kBAAc,OAAO,GAAG,OAAO,SAAS,GAAG,OAAO;AAClD,kBAAc,oBAAoB;AAClC,kBAAc,uBAAuB;AACrC,kBAAc,oBAAoB;;GAGnC,MAAM,gBAAgB,wBAAwB,IAAI;AAClD,OAAI,eAAe,SAAS,cAAc,UAAU,WAAW;AAC9D,uBAAmB,cAAc;AACjC,kBAAc,eAAe;AAC7B,kBAAc,iBAAiB,cAAc,UAAU,cAAc;AACrE,kBAAc,gBAAgB,cAAc,UAAU;;GAQvD,MAAM,aAJW,UAChB,kBACM,MAAM,GAAG,QAAQ,YAAY,CAAC,KAAK,CACzC,CAC2B,KAAK,QAAQ;IACxC,MAAM,OAAO,WAAW,OAAO,KAAK,SAAS;AAC7C,SAAK,SAAS,WAAW,KAAK;AAC9B,WAAO;KACN;GAEF,MAAM,WAAoC,EAAE;AAC5C,QAAK,MAAM,QAAQ,WAClB,UAAS,OAAO,KAAK,eAAe,IAAI,KAAK;GAI9C,MAAM,cAAc,UAAU,qBAC7B,EACE,OAAO;IACP,gBAAgB,OAAO,aAAa;IACpC,IAAI,OAAO,aAAa;IACxB,OAAO,OAAO,aAAa;IAC3B,YAAY,OAAO,aAAa;IAChC,aAAa,OAAO,aAAa;IACjC,QAAQ,OAAO,aAAa;IAC5B,SAAS,OAAO,aAAa;IAC7B,CAAC,CACD,KAAK,OAAO,aAAa,CACzB,QAAQ,KAAK,OAAO,aAAa,YAAY,CAAC,CAC9C,MAAM,GAAG,CACT,KAAK,CACP;GACD,MAAM,iCAAiB,IAAI,KAAuB;AAC1B,aACvB,yBAEC,MAAM,GAAG,QAAQ,wDAAwD,CAAC,KAAK,CAIhF,CACe,SAAS,YAAY;IACpC,MAAM,QAAQ,aAAa,QAAQ,eAAgC;AACnE,QAAI,MAAM,OAAQ,gBAAe,IAAI,OAAO,QAAQ,kBAAkB,GAAG,EAAE,MAAM;KAChF;GACF,MAAM,gBAAgB,YAAY,KAAK,QAAQ;IAC9C,MAAM,QAAQ,WAAW,eAAe,IAAI,OAAO,IAAI,kBAAkB,GAAG,CAAC,GAAG,KAAA;AAChF,WAAO;KACN,GAAG;KACH,QAAQ,cAAc,IAAI;KAC1B,SAAS,OAAO,SAAS,MAAM,KAAK;KACpC;KACA;GACF,MAAM,qBAAqB,OAAO,cAAc,IAAI,SAAS,GAAG,CAAC,MAAM;GAEvE,MAAM,cAAuC;IAC5C,GAAG;IACH,wBAAwB,yBAAyB,oBAAoB,MAAM,GAAG,EAAE,SAAS;IACzF,OAAO;IACP,SAAS;IACT,MAAM,EAAE;IACR,MAAM,EAAE;IACR;GACD,MAAM,gBAAgB,UAAU,uBAAuB,MAAM,0BAA0B,CAAC;GACxF,MAAM,gBAAgB,UAAU,uBAAuB,MAAM,qBAAqB,QAAQ,CAAC;GAC3F,MAAM,sBAAsB,MAAM,0BAA0B,OAAO,OAAO;GAC1E,MAAM,cAAc,UAAU,qBAC7B,wBAAwB,qBAAqB,SAAS,CACtD;GACD,IAAI,eAA0C,EAAE;AAChD,OAAI,uBAAuB,YAAY,OAAO,2BAC7C,KAAI;AACH,mBAAe,MAAM,4BAA4B,OAAO;WACjD;AACP,mBAAe,EAAE;;AAInB,OAAI,qBAAqB,QAAQ,mBAAmB,WAAW,mBAAmB,EAAE;AACnF,uBAAmB;AACnB,kBAAc,eAAe;AAC7B,kBAAc,gBAAgB,mBAAmB,QAAQ,qBAAqB,GAAG;AACjF,gBAAY,eAAe;AAC3B,gBAAY,gBAAgB,mBAAmB,QAAQ,qBAAqB,GAAG;;AAGhF,OAAI,qBAAqB,MAAM;IAC9B,MAAM,aAAa,IAAI,IACtB,WAAW,KAAK,SACf,OAAQ,KAAK,QAAgD,cAAc,GAAG,CAC9E,CACD;IACD,MAAM,uBAAuB,QAC5B,cAAc,MACb,cAAc,GAAG,WAAW,WAC5B,YAAY,cAAc,GAAG,YAAY,CAC1C;IACD,MAAM,aACL,WAAW,SAAS,KACpB,WAAW,OACT,SACA,OAAQ,KAAK,QAAoC,cAAc,GAAG,KAAK,UACxE;AACF,QAAI;SACiB,WAAW,IAAI,SAAS,IAAI,WAAW,IAAI,WAAW,CACzD,oBAAmB;cAC3B,WAAY,oBAAmB;cAC/B,WAAW,SAAS,EAAG,oBAAmB;eACzC,WAAW,IAAI,WAAW,CACpC,oBAAmB;aACT,WACV,oBAAmB;aACT,WAAW,SAAS,KAAK,CAAC,WAAW,IAAI,SAAS,CAC5D,oBAAmB;AAEpB,kBAAc,eAAe;AAC7B,gBAAY,eAAe;;GAG5B,MAAM,kBAA2C;IAChD,GAAG;IACH,QAAQ;IACR,OAAO;IACP,UAAU,cAAc,MAAM,GAAG,EAAE;IACnC,gBAAgB;IAChB,gBAAgB;IAChB;IACA;AACD,OAAI,uBAAuB,SAC1B,iBAAgB,gBAAgB;AAEjC,UAAO,EAAE,KAAK,gBAAgB;;GAE9B;AAGF,KAAI,IAAI,oBAAoB,MAAM;EACjC,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,WAAW,UAAU,EAAE,IAAI,MAAM,qBAAqB,CAAC;GAG7D,MAAM,QAFO,MAAM,GAAG,QAAQ,YAAY,CAAC,KAAK,CAE7B,KAAK,QAAQ,WAAW,OAAO,KAAK,SAAS,CAAC;AACjE,UAAO,EAAE,KAAK;IAAE,OAAO;IAAO,UAAU,CAAC;IAAU,CAAC;;GAEpD;AAGF,KAAI,IAAI,qBAAqB,MAAM;EAClC,MAAM,QAAQ,UAAU;EACxB;AACC,0BAAuB,MAAM;GAC7B,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;GACvC,MAAM,gBAAgB,UAAU,EAAE,IAAI,MAAM,gBAAgB,CAAC;GAC7D,MAAM,QAAQ,EAAE,QAAQ,CAAC,KAAK,OAAO,OAAO;GAC5C,MAAM,OAAO,gBACV,MAAM,QAAQ,OAAO,OAAO,aAAa,CAAC,KAAK,GAC/C,MACC,MAAM,IAAI,GAAG,OAAO,OAAO,QAAQ,SAAS,EAAE,GAAG,OAAO,OAAO,QAAQ,cAAc,CAAC,CAAC,CACvF,QAAQ,OAAO,OAAO,aAAa,CACnC,KAAK;AACT,UAAO,EAAE,KAAK,EAAE,OAAO,MAAM,CAAC;;GAE9B;AAGF,KAAI,IAAI,uBAAuB,MAAM;EACpC,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;GACvC,IAAI,QAAQ,SAAS,EAAE,IAAI,MAAM,QAAQ,EAAE,GAAG;AAC9C,OAAI,SAAS,EAAG,QAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,EAAE,IAAI;AAC9D,WAAQ,KAAK,IAAI,OAAO,IAAI;GAC5B,MAAM,OAAO,EACX,OAAO;IACP,gBAAgB,OAAO,aAAa;IACpC,IAAI,OAAO,aAAa;IACxB,OAAO,OAAO,aAAa;IAC3B,YAAY,OAAO,aAAa;IAChC,aAAa,OAAO,aAAa;IACjC,QAAQ,OAAO,aAAa;IAC5B,SAAS,OAAO,aAAa;IAC7B,CAAC,CACD,KAAK,OAAO,aAAa,CACzB,QAAQ,KAAK,OAAO,aAAa,YAAY,CAAC,CAC9C,MAAM,MAAM,CACZ,KAAK;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,MAAM,CAAC;;GAE9B;AAGF,KAAI,IAAI,sBAAsB,MAAM;EACnC,MAAM,QAAQ,UAAU;EACxB;AAEC,OAAI,CADa,UAAU,EAAE,IAAI,MAAM,qBAAqB,CAAC,CAE5D,QAAO,EAAE,KAAK;IACb,UAAU;IACV,qBAAqB;IACrB,CAAC;GAEH,MAAM,SAAS,2BAA2B;GAC1C,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;GACvC,MAAM,YAAY,EAChB,OAAO;IACP,WAAW,OAAO,WAAW;IAC7B,YAAY,OAAO,WAAW;IAC9B,aAAa,OAAO,WAAW;IAC/B,CAAC,CACD,KAAK,OAAO,WAAW,CACvB,MAAM,EAAE,CACR,KAAK;GAEP,IAAI;GACJ,IAAI;GACJ,IAAI;AAEJ,OAAI,WAAW;AACd,eAAW,OAAO,UAAU,UAAU;AACtC,gBAAY,OAAO,UAAU,WAAW;AACxC,kBAAc,OAAO,UAAU,YAAY;SAG3C,KAAI;IACH,MAAM,CAAC,IAAI,MAAM,qBAAqB,MAAM,IAAI,EAAE,SAAS,aAAa,EAAE,CAAC;AAC3E,eAAW;AACX,kBAAc;AAMd,gBALe,EACb,OAAO,EAAE,YAAY,OAAO,WAAW,YAAY,CAAC,CACpD,KAAK,OAAO,WAAW,CACvB,MAAM,GAAG,OAAO,WAAW,WAAW,GAAG,CAAC,CAC1C,KAAK,EACa,cAAc;WAC3B;AACP,WAAO,EAAE,KAAK,EAAE,OAAO,+BAA+B,EAAE,IAAI;;AAI9D,OAAI,CAAC,YAAY,CAAC,YACjB,QAAO,EAAE,KAAK,EAAE,OAAO,sBAAsB,EAAE,IAAI;AAGpD,UAAO,EAAE,KAAK;IACb,WAAW;IACX;IACA,YAAY,aAAa;IACzB,qBAAqB;IACrB,WAAW,0BAA0B,OAAO;IAC5C,CAAC;;GAEF;AAOF,KAAI,KAAK,0BAA0B,OAAO,MAAM;EAC/C,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;GACvC,MAAM,OAAO,MAAM,EAAE,IAAI,MAA+B;GACxD,MAAM,eAAe,OAAO,KAAK,kBAAkB,GAAG,CAAC,MAAM;GAC7D,MAAM,OAAO,OAAO,KAAK,QAAQ,GAAG,CAAC,MAAM;AAC3C,OAAI,CAAC,aAAc,QAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;AAC3E,OAAI,CAAC,KAAM,QAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,EAAE,IAAI;AAMzD,OAAI,CALW,EACb,OAAO,EAAE,gBAAgB,OAAO,UAAU,gBAAgB,CAAC,CAC3D,KAAK,OAAO,UAAU,CACtB,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CACxD,KAAK,CACM,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAC5D,KAAE,OAAO,OAAO,UAAU,CACxB,IAAI,EAAE,MAAM,CAAC,CACb,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CACxD,KAAK;AACP,UAAO,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC;;GAE3B;AAEF,KAAI,KAAK,iBAAiB,OAAO,MAAM;EACtC,MAAM,QAAQ,UAAU;EACxB,IAAI,OAAgC,EAAE;AACtC,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE;;AAGV,MAAI,CADW,2BAA2B,CAC9B,YACX,QAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,EAAE,IAAI;EAE/C,MAAM,UACL,OAAO,KAAK,YAAY,YAAY,KAAK,QAAQ,MAAM,GAAG,KAAK,QAAQ,MAAM,GAAG;EACjF,MAAM,kBACL,OAAO,KAAK,mBAAmB,YAAY,KAAK,eAAe,MAAM,GAClE,KAAK,eAAe,MAAM,GAC1B;EACJ,IAAI;AACJ,MAAI,SAAS;GACZ,MAAM,SAAS,2BAA2B,OAAO,QAAQ;AACzD,OAAI,CAAC,OAAQ,QAAO,EAAE,KAAK,EAAE,OAAO,wBAAwB,EAAE,IAAI;AAClE,aAAU,CAAC,OAAO;aACR,gBAIV,WAH0B,MAAM,GAC9B,QAAQ,iEAAiE,CACzE,IAAI,gBAAgB,CAEpB,KAAK,QAAQ,OAAO,IAAI,kBAAkB,GAAG,CAAC,MAAM,CAAC,CACrD,OAAO,QAAQ;MAKjB,WAHoB,MAAM,GAAG,QAAQ,wCAAwC,CAAC,KAAK,CAG7D,KAAK,QAAQ,OAAO,IAAI,kBAAkB,GAAG,CAAC,MAAM,CAAC,CAAC,OAAO,QAAQ;EAE5F,MAAM,QAAQ,EAAE;AAChB,OAAK,MAAM,UAAU,SAAS;GAC7B,MAAM,SAAS,MAAM,YAAY,MAAM,IAAI,OAAO;AAClD,SAAM,KAAK;IAAE,gBAAgB;IAAQ,GAAG;IAAQ,CAAC;;AAElD,SAAO,EAAE,KAAK,EAAE,OAAO,CAAC;GACvB;AAEF,KAAI,KAAK,yBAAyB,OAAO,MAAM;EAC9C,MAAM,QAAQ,UAAU;EACxB,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,eAAe,OAAO,KAAK,kBAAkB,GAAG,CAAC,MAAM;AAC7D,MAAI,CAAC,aAAc,QAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;EAC3E,MAAM,UAAU,MAAM,QAAQ,KAAK,QAAQ,GACxC,KAAK,QACJ,QAAQ,UAA2B,OAAO,UAAU,SAAS,CAC7D,KAAK,UAAU,MAAM,MAAM,CAAC,CAC5B,OAAO,QAAQ,GAChB;EACH,MAAM,UAAU,MAAM,QAAQ,KAAK,QAAQ,GACxC,KAAK,QACJ,QAAQ,UAA2B,OAAO,UAAU,SAAS,CAC7D,KAAK,UAAU,MAAM,MAAM,CAAC,CAC5B,OAAO,QAAQ,GAChB;EACH,MAAM,gBAAgB,QAAQ,KAAK,eAAe;EAClD,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;AAMvC,MAAI,CALW,EACb,OAAO,EAAE,gBAAgB,OAAO,UAAU,gBAAgB,CAAC,CAC3D,KAAK,OAAO,UAAU,CACtB,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CACxD,KAAK,CACM,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAC5D,IAAE,OAAO,OAAO,UAAU,CACxB,IAAI;GACJ,uBAAuB,gBAAgB,OAAO,KAAK,UAAU,WAAW,EAAE,CAAC;GAC3E,uBAAuB,gBAAgB,OAAO,KAAK,UAAU,WAAW,EAAE,CAAC;GAC3E,CAAC,CACD,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CACxD,KAAK;EACP,MAAM,MAAM,EACV,OAAO;GACP,uBAAuB,OAAO,UAAU;GACxC,uBAAuB,OAAO,UAAU;GACxC,CAAC,CACD,KAAK,OAAO,UAAU,CACtB,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CACxD,KAAK;AACP,MAAI,CAAC,IAAK,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AACzD,SAAO,EAAE,KAAK;GACb,IAAI;GACJ,eAAe,oBAAoB,KAAK,uBAAuB,OAAO,aAAa,CAAC;GACpF,CAAC;GACD;AAEF,KAAI,KAAK,4BAA4B,OAAO,MAAM;EACjD,MAAM,QAAQ,UAAU;AACxB,yBAAuB,MAAM;EAC7B,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,eAAe,OAAO,KAAK,kBAAkB,GAAG,CAAC,MAAM;AAC7D,MAAI,CAAC,aAAc,QAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;EAC3E,MAAM,mBACL,KAAK,YAAY,OAAO,KAAA,IAAY,OAAO,KAAK,YAAY,GAAG,CAAC,MAAM,IAAI;EAC3E,MAAM,oBACL,OAAO,KAAK,wBAAwB,YAAY,KAAK,sBAAsB,KAAA;EAC5E,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;EACvC,MAAM,OAAO,EACX,OAAO;GACP,gBAAgB,OAAO,UAAU;GACjC,UAAU,OAAO,UAAU;GAC3B,qBAAqB,OAAO,UAAU;GACtC,CAAC,CACD,KAAK,OAAO,UAAU,CACtB,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CACxD,KAAK;AACP,MAAI,CAAC,KAAM,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;EAE1D,IAAI,cAAc,KAAK,YAAY;EACnC,IAAI,wBAAwB,QAAQ,KAAK,oBAAoB;AAC7D,MAAI,qBAAqB,KAAA,GAAW;AACnC,iBAAc;AACd,OAAI,kBAAkB;IACrB,MAAM,QAAQ,EACZ,OAAO;KACP,UAAU,OAAO,OAAO;KACxB,UAAU,OAAO,OAAO;KACxB,QAAQ,OAAO,OAAO;KACtB,CAAC,CACD,KAAK,OAAO,OAAO,CACnB,MAAM,GAAG,OAAO,OAAO,UAAU,iBAAiB,CAAC,CACnD,KAAK;AACP,QAAI,CAAC,MAAO,QAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,EAAE,IAAI;AAC5D,QAAI,MAAM,WAAW,SAAU,QAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,EAAE,IAAI;AAChF,4BAAwB,qBAAqB,QAAQ,MAAM,SAAS;SAEpE,yBAAwB,qBAAqB;aAEpC,sBAAsB,KAAA,GAAW;AAC3C,2BAAwB;AACxB,OAAI,kBACH,eAAc,MAAM;YACV,gBAAgB,MAAM,QAChC,eAAc;;AAIhB,IAAE,OAAO,OAAO,UAAU,CACxB,IAAI;GACJ,UAAU;GACV,qBAAqB,wBAAwB,IAAI;GACjD,CAAC,CACD,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CACxD,KAAK;AACP,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,UAAU;GAAa,qBAAqB;GAAuB,CAAC;GAC7F;AAEF,KAAI,KAAK,oBAAoB,OAAO,MAAM;EACzC,MAAM,QAAQ,UAAU;AACxB,yBAAuB,MAAM;EAC7B,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,cAAc,OAAO,KAAK,gBAAgB,GAAG,CAAC,MAAM;AAC1D,MAAI,CAAC,YAAa,QAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,EAAE,IAAI;EACxE,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;EACvC,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;EACpC,MAAM,QAAQ;GACb,UAAU,YAAY;GACtB,cAAc;GACd,UAAU;GACV,QAAQ;GACR,sBAAsB;GACtB,YAAY;GACZ,YAAY;GACZ;AACD,IAAE,OAAO,OAAO,OAAO,CAAC,OAAO,MAAM,CAAC,KAAK;AAC3C,SAAO,EAAE,KAAK,MAAM;GACnB;AAEF,KAAI,KAAK,2BAA2B,OAAO,MAAM;EAChD,MAAM,QAAQ,UAAU;AACxB,yBAAuB,MAAM;EAC7B,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,UAAU,OAAO,KAAK,YAAY,GAAG,CAAC,MAAM;EAClD,MAAM,cAAc,OAAO,KAAK,gBAAgB,GAAG,CAAC,MAAM;AAC1D,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,EAAE,IAAI;AAChE,MAAI,CAAC,YAAa,QAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,EAAE,IAAI;EACxE,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;EACvC,MAAM,QAAQ,EAAE,QAAQ,CAAC,KAAK,OAAO,OAAO,CAAC,MAAM,GAAG,OAAO,OAAO,UAAU,QAAQ,CAAC,CAAC,KAAK;AAC7F,MAAI,CAAC,MAAO,QAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,EAAE,IAAI;EAC5D,MAAM,6BAAY,IAAI,MAAM,EAAC,aAAa;AAC1C,IAAE,OAAO,OAAO,OAAO,CACrB,IAAI;GAAE,cAAc;GAAa,YAAY;GAAW,CAAC,CACzD,MAAM,GAAG,OAAO,OAAO,UAAU,QAAQ,CAAC,CAC1C,KAAK;AACP,SAAO,EAAE,KAAK;GAAE,GAAG;GAAO,cAAc;GAAa,YAAY;GAAW,CAAC;GAC5E;AAEF,KAAI,KAAK,0BAA0B,OAAO,MAAM;EAC/C,MAAM,QAAQ,UAAU;AACxB,yBAAuB,MAAM;EAC7B,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,iBAAiB,OAAO,KAAK,oBAAoB,GAAG,CAAC,MAAM;EACjE,MAAM,mBAAmB,OAAO,KAAK,sBAAsB,GAAG,CAAC,MAAM;AACrE,MAAI,CAAC,eAAgB,QAAO,EAAE,KAAK,EAAE,OAAO,6BAA6B,EAAE,IAAI;AAC/E,MAAI,CAAC,iBAAkB,QAAO,EAAE,KAAK,EAAE,OAAO,+BAA+B,EAAE,IAAI;AACnF,MAAI,mBAAmB,iBAAkB,QAAO,EAAE,KAAK,EAAE,OAAO,yBAAyB,EAAE,IAAI;EAC/F,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;EACvC,MAAM,UAAU,EACd,QAAQ,CACR,KAAK,OAAO,OAAO,CACnB,MAAM,GAAG,OAAO,OAAO,UAAU,eAAe,CAAC,CACjD,KAAK;EACP,MAAM,YAAY,EAChB,QAAQ,CACR,KAAK,OAAO,OAAO,CACnB,MAAM,GAAG,OAAO,OAAO,UAAU,iBAAiB,CAAC,CACnD,KAAK;AACP,MAAI,CAAC,WAAW,CAAC,UAAW,QAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,EAAE,IAAI;AAC5E,MAAI,QAAQ,WAAW,SAAU,QAAO,EAAE,KAAK,EAAE,OAAO,4BAA4B,EAAE,IAAI;AAC1F,MAAI,UAAU,WAAW,SAAU,QAAO,EAAE,KAAK,EAAE,OAAO,8BAA8B,EAAE,IAAI;AAC9F,MAAI,UAAU,YAAY,UAAU,aAAa,MAAM,QACtD,QAAO,EAAE,KAAK,EAAE,OAAO,8CAA8C,EAAE,IAAI;EAE5E,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;EACpC,MAAM,cAAc,MAAM,GAAG,kBAAkB;GAC9C,MAAM,aAAa,EACjB,OAAO,OAAO,UAAU,CACxB,IAAI,EAAE,UAAU,gBAAgB,CAAC,CACjC,MAAM,GAAG,OAAO,UAAU,UAAU,iBAAiB,CAAC,CACtD,KAAK;AACP,OAAI,QAAQ,SACX,GAAE,OAAO,OAAO,UAAU,CACxB,IAAI,EAAE,qBAAqB,GAAG,CAAC,CAC/B,MAAM,GAAG,OAAO,UAAU,UAAU,eAAe,CAAC,CACpD,KAAK;AAER,KAAE,OAAO,OAAO,OAAO,CACrB,IAAI;IAAE,QAAQ;IAAU,sBAAsB;IAAgB,YAAY;IAAK,CAAC,CAChF,MAAM,GAAG,OAAO,OAAO,UAAU,iBAAiB,CAAC,CACnD,KAAK;AACP,UAAO,OAAO,WAAW,WAAW,EAAE;IACrC,EAAE;AACJ,SAAO,EAAE,KAAK,EAAE,cAAc,aAAa,CAAC;GAC3C;AAEF,KAAI,KAAK,+BAA+B,OAAO,MAAM;EACpD,MAAM,QAAQ,UAAU;EACxB,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,UAAU,OAAO,KAAK,YAAY,GAAG,CAAC,MAAM;AAClD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,EAAE,IAAI;AAChE,MAAI,YAAY,MAAM,QACrB,QAAO,EAAE,KAAK,EAAE,OAAO,mDAAmD,EAAE,IAAI;EAEjF,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;EACvC,MAAM,QAAQ,EAAE,QAAQ,CAAC,KAAK,OAAO,OAAO,CAAC,MAAM,GAAG,OAAO,OAAO,UAAU,QAAQ,CAAC,CAAC,KAAK;AAC7F,MAAI,CAAC,MAAO,QAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,EAAE,IAAI;AAC5D,MAAI,MAAM,WAAW,SAAU,QAAO,EAAE,KAAK,EAAE,OAAO,oBAAoB,EAAE,IAAI;EAChF,MAAM,uBAAM,IAAI,MAAM,EAAC,aAAa;AACpC,IAAE,OAAO,OAAO,OAAO,CACrB,IAAI;GAAE,QAAQ;GAAe,YAAY;GAAK,CAAC,CAC/C,MAAM,GAAG,OAAO,OAAO,UAAU,QAAQ,CAAC,CAC1C,KAAK;AACP,IAAE,OAAO,OAAO,UAAU,CACxB,IAAI,EAAE,UAAU,MAAM,CAAC,CACvB,MAAM,GAAG,OAAO,UAAU,UAAU,QAAQ,CAAC,CAC7C,KAAK;AACP,SAAO,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC;GAC1B;AAEF,KAAI,KAAK,kCAAkC,OAAO,MAAM;EACvD,MAAM,QAAQ,UAAU;EACxB,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,iBAAiB,OAAO,KAAK,oBAAoB,GAAG,CAAC,MAAM;AACjE,MAAI,CAAC,eAAgB,QAAO,EAAE,KAAK,EAAE,OAAO,6BAA6B,EAAE,IAAI;EAC/E,MAAM,UAAU,wBAAwB,OAAO,eAAe;AAC9D,MAAI,WAAW,EAAG,QAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;AAC1E,SAAO,EAAE,KAAK;GAAE,IAAI;GAAM,kBAAkB;GAAgB;GAAS,CAAC;GACrE;AAEF,KAAI,KAAK,qCAAqC,OAAO,MAAM;EAC1D,MAAM,QAAQ,UAAU;EACxB,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,eAAe,OAAO,KAAK,kBAAkB,GAAG,CAAC,MAAM;EAC7D,MAAM,cAAc,OAAO,KAAK,eAAe,GAAG,CAAC,MAAM;AACzD,MAAI,CAAC,aAAc,QAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;AAC3E,MAAI,CAAC,YAAa,QAAO,EAAE,KAAK,EAAE,OAAO,wBAAwB,EAAE,IAAI;AACvE,MAAI;GACH,MAAM,SAAS,MAAM,qBAAqB,OAAO;IAAE;IAAc;IAAa,CAAC;AAC/E,OAAI,CAAC,OAAO,GACX,QAAO,EAAE,KACR;IAAE,OAAO,OAAO;IAAO,QAAQ,OAAO;IAAQ,EAC9C,EAAE,QAAQ,OAAO,QAA2B,CAC5C;AAEF,UAAO,EAAE,KAAK;IACb,IAAI;IACJ,gBAAgB,OAAO;IACvB,SAAS,OAAO;IAChB,SAAS,OAAO;IAChB,MAAM,OAAO;IACb,oBAAoB;IACpB,CAAC;WACM,OAAO;AACf,UAAO,EAAE,KACR;IACC,OAAO;IACP,QAAQ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAC9D,EACD,EAAE,QAAQ,KAAK,CACf;;GAED;AAEF,KAAI,KAAK,4BAA4B,OAAO,MAAM;EACjD,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,UAAU,OAAO,KAAK,YAAY,GAAG,CAAC,MAAM;EAClD,MAAM,iBAAiB,KAAK,mBAAmB,OAAO,OAAO,OAAO,KAAK,mBAAmB,GAAG;EAC/F,MAAM,SAAS,OAAO,KAAK,UAAU,aAAa,CAAC,MAAM;EACzD,MAAM,WAAW,oBAAoB,KAAK,UAAU;AACpD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,EAAE,IAAI;AAChE,MAAI,KAAK,mBAAmB,QAAQ,OAAO,KAAK,oBAAoB,SACnE,QAAO,EAAE,KAAK,EAAE,OAAO,kCAAkC,EAAE,IAAI;AAEhE,MAAI,CAAC,CAAC,cAAc,oBAAoB,CAAC,SAAS,OAAO,CACxD,QAAO,EAAE,KAAK,EAAE,OAAO,kDAAkD,EAAE,IAAI;AAEhF,MAAI,YAAY,KAAM,QAAO,EAAE,KAAK,EAAE,OAAO,qCAAqC,EAAE,IAAI;AACxF,MAAI;GACH,MAAM,SAAS,2BAA2B;GAC1C,MAAM,SAAS,MAAM,8BAA8B;IAClD;IACA;IACA;IACA;IACA,WAAW;IACX,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,UAAO,EAAE,KAAK,OAAO;WACb,OAAO;AACf,UAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EAAE,IAAI;;GAErF;AAEF,KAAI,KAAK,4BAA4B,OAAO,MAAM;EACjD,MAAM,QAAQ,UAAU;EACxB,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,cAAc,OAAO,KAAK,UAAU,GAAG,CAAC,MAAM;AACpD,MAAI,CAAC,YAAa,QAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,EAAE,IAAI;AAClE,MAAI;GACH,MAAM,SAAS,MAAM,8BAA8B;IAAE;IAAa,QAAQ,MAAM;IAAQ,CAAC;AACzF,UAAO,EAAE,KAAK,OAAO;WACb,OAAO;AACf,UAAO,EAAE,KAAK,EAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM,EAAE,EAAE,IAAI;;GAErF;AAEF,KAAI,IAAI,iCAAiC,OAAO,MAAM;EACrD,MAAM,SAAS,+BAA+B;AAC9C,SAAO,EAAE,KAAK,OAAO;GACpB;AAEF,KAAI,IAAI,iCAAiC,OAAO,MAAM;EACrD,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,kBAAkB,UAAU,EAAE,IAAI,MAAM,mBAAmB,CAAC;AAClE,MAAI;GACH,MAAM,QAAQ,MAAM,4BAA4B;IAC/C;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,UAAO,EAAE,KAAK;IAAE;IAAO;IAAQ,CAAC;WACxB,OAAO;GACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAO,EAAE,KAAK;IAAE,OAAO;IAAS;IAAQ,EAAE,IAAI;;GAE9C;AAEF,KAAI,KAAK,iCAAiC,OAAO,MAAM;EACtD,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK;IAAE,OAAO;IAAgB;IAAQ,EAAE,IAAI;;EAEtD,MAAM,UAAU,OAAO,KAAK,YAAY,GAAG,CAAC,MAAM;EAClD,MAAM,cAAc,OAAO,KAAK,gBAAgB,GAAG,CAAC,MAAM,IAAI;AAC9D,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI;GACH,MAAM,QAAQ,MAAM,6BAA6B;IAChD;IACA;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM;IAAO;IAAQ,CAAC;WAClC,OAAO;AACf,UAAO,EAAE,KAAK;IAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE;IAAQ,EAAE,IAAI;;GAE7F;AAEF,KAAI,KAAK,kDAAkD,OAAO,MAAM;EACvE,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,UAAU,OAAO,EAAE,IAAI,MAAM,WAAW,IAAI,GAAG,CAAC,MAAM;AAC5D,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;EACxE,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK;IAAE,OAAO;IAAgB;IAAQ,EAAE,IAAI;;EAEtD,MAAM,cAAc,OAAO,KAAK,gBAAgB,GAAG,CAAC,MAAM;AAC1D,MAAI,CAAC,YAAa,QAAO,EAAE,KAAK;GAAE,OAAO;GAAyB;GAAQ,EAAE,IAAI;AAChF,MAAI;GACH,MAAM,QAAQ,MAAM,6BAA6B;IAChD;IACA;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,OAAI,CAAC,MAAO,QAAO,EAAE,KAAK;IAAE,OAAO;IAAmB;IAAQ,EAAE,IAAI;AACpE,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM;IAAO;IAAQ,CAAC;WAClC,OAAO;AACf,UAAO,EAAE,KAAK;IAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE;IAAQ,EAAE,IAAI;;GAE7F;AAEF,KAAI,KAAK,mDAAmD,OAAO,MAAM;EACxE,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,UAAU,OAAO,EAAE,IAAI,MAAM,WAAW,IAAI,GAAG,CAAC,MAAM;AAC5D,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI;GACH,MAAM,QAAQ,MAAM,8BAA8B;IACjD;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,OAAI,CAAC,MAAO,QAAO,EAAE,KAAK;IAAE,OAAO;IAAuC;IAAQ,EAAE,IAAI;AACxF,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM;IAAO;IAAQ,CAAC;WAClC,OAAO;AACf,UAAO,EAAE,KAAK;IAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE;IAAQ,EAAE,IAAI;;GAE7F;AAEF,KAAI,KAAK,qDAAqD,OAAO,MAAM;EAC1E,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,UAAU,OAAO,EAAE,IAAI,MAAM,WAAW,IAAI,GAAG,CAAC,MAAM;AAC5D,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI;GACH,MAAM,QAAQ,MAAM,gCAAgC;IACnD;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,OAAI,CAAC,MAAO,QAAO,EAAE,KAAK;IAAE,OAAO;IAAmC;IAAQ,EAAE,IAAI;AACpF,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM;IAAO;IAAQ,CAAC;WAClC,OAAO;AACf,UAAO,EAAE,KAAK;IAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE;IAAQ,EAAE,IAAI;;GAE7F;AAEF,KAAI,KAAK,kCAAkC,OAAO,MAAM;EACvD,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK;IAAE,OAAO;IAAgB;IAAQ,EAAE,IAAI;;EAEtD,MAAM,UAAU,6BAA6B,OAAO,KAAK,YAAY,GAAG,CAAC,MAAM,EAAE,OAAO;EACxF,MAAM,iBAAiB,KAAK,mBAAmB,OAAO,OAAO,OAAO,KAAK,mBAAmB,GAAG;EAC/F,MAAM,SAAS,OAAO,KAAK,UAAU,aAAa,CAAC,MAAM;EACzD,MAAM,WAAW,oBAAoB,KAAK,UAAU;AACpD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI,KAAK,mBAAmB,QAAQ,OAAO,KAAK,oBAAoB,SACnE,QAAO,EAAE,KAAK;GAAE,OAAO;GAAkC;GAAQ,EAAE,IAAI;AAExE,MAAI,CAAC,CAAC,cAAc,oBAAoB,CAAC,SAAS,OAAO,CACxD,QAAO,EAAE,KAAK;GAAE,OAAO;GAAkD;GAAQ,EAAE,IAAI;AAExF,MAAI,YAAY,KACf,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqC;GAAQ,EAAE,IAAI;AAE3E,MAAI;GACH,MAAM,SAAS,MAAM,8BAA8B;IAClD;IACA;IACA;IACA;IACA,WAAW;IACX,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,UAAO,EAAE,KAAK;IAAE,GAAG;IAAQ;IAAQ,CAAC;WAC5B,OAAO;AACf,UAAO,EAAE,KAAK;IAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE;IAAQ,EAAE,IAAI;;GAE7F;AAEF,KAAI,IAAI,wCAAwC,OAAO,MAAM;EAC5D,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,UAAU,6BAA6B,EAAE,IAAI,MAAM,WAAW,EAAE,OAAO;AAC7E,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI;GACH,MAAM,QAAQ,MAAM,kCAAkC;IACrD;IACA,WAAW,OAAO;IAClB,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,UAAO,EAAE,KAAK;IAAE;IAAO,UAAU;IAAS;IAAQ,CAAC;WAC3C,OAAO;GACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAO,EAAE,KAAK;IAAE,OAAO;IAAS;IAAQ,EAAE,IAAI;;GAE9C;AAEF,KAAI,KAAK,4DAA4D,OAAO,MAAM;EACjF,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,YAAY,OAAO,EAAE,IAAI,MAAM,aAAa,IAAI,GAAG,CAAC,MAAM;AAChE,MAAI,CAAC,UAAW,QAAO,EAAE,KAAK;GAAE,OAAO;GAAuB;GAAQ,EAAE,IAAI;AAC5E,MAAI;GACH,MAAM,SAAS,MAAM,mCAAmC;IACvD;IACA,SAAS;IACT,YAAY;IACZ,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,OAAI,CAAC,OAAQ,QAAO,EAAE,KAAK;IAAE,OAAO;IAA0B;IAAQ,EAAE,IAAI;AAC5E,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,SAAS;IAAQ;IAAQ,CAAC;WAC5C,OAAO;GACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,UAAO,EAAE,KACR;IAAE,OAAO;IAAS;IAAQ,EAC1B,QAAQ,SAAS,oBAAoB,IAAI,QAAQ,SAAS,YAAY,GAAG,MAAM,IAC/E;;GAED;AAEF,KAAI,KAAK,yDAAyD,OAAO,MAAM;EAC9E,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,YAAY,OAAO,EAAE,IAAI,MAAM,aAAa,IAAI,GAAG,CAAC,MAAM;AAChE,MAAI,CAAC,UAAW,QAAO,EAAE,KAAK;GAAE,OAAO;GAAuB;GAAQ,EAAE,IAAI;AAC5E,MAAI;GACH,MAAM,SAAS,MAAM,mCAAmC;IACvD;IACA,SAAS;IACT,YAAY;IACZ,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,OAAI,CAAC,OAAQ,QAAO,EAAE,KAAK;IAAE,OAAO;IAA0B;IAAQ,EAAE,IAAI;AAC5E,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,SAAS;IAAQ;IAAQ,CAAC;WAC5C,OAAO;GACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;AACtE,UAAO,EAAE,KACR;IAAE,OAAO;IAAS;IAAQ,EAC1B,QAAQ,SAAS,oBAAoB,IAAI,QAAQ,SAAS,YAAY,GAAG,MAAM,IAC/E;;GAED;AAEF,KAAI,IAAI,kCAAkC,OAAO,MAAM;EACtD,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,UAAU,6BAA6B,EAAE,IAAI,MAAM,WAAW,EAAE,OAAO;AAC7E,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI;GACH,MAAM,QAAQ,MAAM,6BAA6B;IAChD;IACA,iBAAiB,UAAU,EAAE,IAAI,MAAM,mBAAmB,CAAC;IAC3D,WAAW,OAAO;IAClB,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,UAAO,EAAE,KAAK;IAAE;IAAO,UAAU;IAAS;IAAQ,CAAC;WAC3C,OAAO;GACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAO,EAAE,KAAK;IAAE,OAAO;IAAS;IAAQ,EAAE,IAAI;;GAE9C;AAEF,KAAI,KAAK,oDAAoD,OAAO,MAAM;EACzE,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,WAAW,OAAO,EAAE,IAAI,MAAM,YAAY,IAAI,GAAG,CAAC,MAAM;AAC9D,MAAI,CAAC,SAAU,QAAO,EAAE,KAAK;GAAE,OAAO;GAAsB;GAAQ,EAAE,IAAI;EAC1E,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK;IAAE,OAAO;IAAgB;IAAQ,EAAE,IAAI;;EAEtD,MAAM,UAAU,6BAA6B,OAAO,KAAK,YAAY,GAAG,CAAC,MAAM,EAAE,OAAO;EACxF,MAAM,cAAc,OAAO,KAAK,gBAAgB,GAAG,CAAC,MAAM;AAC1D,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI,CAAC,YAAa,QAAO,EAAE,KAAK;GAAE,OAAO;GAAyB;GAAQ,EAAE,IAAI;AAChF,MAAI;GACH,MAAM,SAAS,MAAM,8BAA8B;IAClD;IACA;IACA;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,OAAI,CAAC,OAAQ,QAAO,EAAE,KAAK;IAAE,OAAO;IAAoB;IAAQ,EAAE,IAAI;AACtE,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM;IAAQ;IAAQ,CAAC;WACnC,OAAO;AACf,UAAO,EAAE,KAAK;IAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE;IAAQ,EAAE,IAAI;;GAE7F;AAEF,KAAI,KAAK,qDAAqD,OAAO,MAAM;EAC1E,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,WAAW,OAAO,EAAE,IAAI,MAAM,YAAY,IAAI,GAAG,CAAC,MAAM;AAC9D,MAAI,CAAC,SAAU,QAAO,EAAE,KAAK;GAAE,OAAO;GAAsB;GAAQ,EAAE,IAAI;EAC1E,MAAM,UAAU,6BAA6B,EAAE,IAAI,MAAM,WAAW,EAAE,OAAO;AAC7E,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI;AAOH,OAAI,CANO,MAAM,+BAA+B;IAC/C;IACA;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC,CACO,QAAO,EAAE,KAAK;IAAE,OAAO;IAAoB;IAAQ,EAAE,IAAI;AAClE,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,WAAW;IAAU;IAAQ,CAAC;WAChD,OAAO;AACf,UAAO,EAAE,KAAK;IAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE;IAAQ,EAAE,IAAI;;GAE7F;AAEF,KAAI,KAAK,oDAAoD,OAAO,MAAM;EACzE,MAAM,SAAS,2BAA2B;EAC1C,MAAM,SAAS,8BAA8B,OAAO;AACpD,MAAI,OAAO,cAAc,iBACxB,QAAO,EAAE,KAAK;GAAE,OAAO;GAA8B;GAAQ,EAAE,IAAI;AAEpE,MAAI,CAAC,OAAO,iBACX,QAAO,EAAE,KAAK;GAAE,OAAO;GAAoC;GAAQ,EAAE,IAAI;EAE1E,MAAM,WAAW,OAAO,EAAE,IAAI,MAAM,YAAY,IAAI,GAAG,CAAC,MAAM;AAC9D,MAAI,CAAC,SAAU,QAAO,EAAE,KAAK;GAAE,OAAO;GAAsB;GAAQ,EAAE,IAAI;EAC1E,MAAM,UAAU,6BAA6B,EAAE,IAAI,MAAM,WAAW,EAAE,OAAO;AAC7E,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK;GAAE,OAAO;GAAqB;GAAQ,EAAE,IAAI;AACxE,MAAI;AAOH,OAAI,CANO,MAAM,8BAA8B;IAC9C;IACA;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC,CACO,QAAO,EAAE,KAAK;IAAE,OAAO;IAAoB;IAAQ,EAAE,IAAI;AAClE,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,WAAW;IAAU;IAAQ,CAAC;WAChD,OAAO;AACf,UAAO,EAAE,KAAK;IAAE,OAAO,iBAAiB,QAAQ,MAAM,UAAU,OAAO,MAAM;IAAE;IAAQ,EAAE,IAAI;;GAE7F;AAEF,KAAI,IAAI,8BAA8B,OAAO,MAAM;EAClD,MAAM,UAAU,OAAO,EAAE,IAAI,MAAM,WAAW,IAAI,GAAG,CAAC,MAAM;AAC5D,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,EAAE,IAAI;EAChE,MAAM,SAAS,2BAA2B;AAC1C,MAAI;GACH,MAAM,QAAQ,MAAM,qCAAqC;IACxD;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC;AACF,UAAO,EAAE,KAAK,EAAE,OAAO,CAAC;WAChB,OAAO;GACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAO,EAAE,KAAK,EAAE,OAAO,SAAS,EAAE,IAAI;;GAEtC;AAEF,KAAI,KAAK,qCAAqC,OAAO,MAAM;EAC1D,IAAI;AACJ,MAAI;AACH,UAAO,MAAM,EAAE,IAAI,MAA+B;UAC3C;AACP,UAAO,EAAE,KAAK,EAAE,OAAO,gBAAgB,EAAE,IAAI;;EAE9C,MAAM,UAAU,OAAO,KAAK,YAAY,GAAG,CAAC,MAAM;AAClD,MAAI,CAAC,QAAS,QAAO,EAAE,KAAK,EAAE,OAAO,qBAAqB,EAAE,IAAI;EAChE,MAAM,SAAS,2BAA2B;AAC1C,MAAI;AAMH,OAAI,CALO,MAAM,sCAAsC;IACtD;IACA,WAAW,OAAO,sBAAsB;IACxC,aAAa,OAAO,8BAA8B;IAClD,CAAC,CACO,QAAO,EAAE,KAAK,EAAE,OAAO,mBAAmB,EAAE,IAAI;AACzD,UAAO,EAAE,KAAK;IAAE,IAAI;IAAM,UAAU;IAAS,CAAC;WACtC,OAAO;GACf,MAAM,UAAU,iBAAiB,QAAQ,MAAM,UAAU;AACzD,UAAO,EAAE,KAAK,EAAE,OAAO,SAAS,EAAE,IAAI;;GAEtC;AAGF,KAAI,OAAO,oCAAoC,MAAM;EACpD,MAAM,QAAQ,UAAU;EACxB;GACC,MAAM,IAAI,QAAQ,MAAM,IAAI,EAAE,QAAQ,CAAC;GACvC,MAAM,eAAe,EAAE,IAAI,MAAM,iBAAiB,EAAE,MAAM;AAC1D,OAAI,CAAC,aAAc,QAAO,EAAE,KAAK,EAAE,OAAO,2BAA2B,EAAE,IAAI;AAM3E,OAAI,CALW,EACb,OAAO,EAAE,gBAAgB,OAAO,UAAU,gBAAgB,CAAC,CAC3D,KAAK,OAAO,UAAU,CACtB,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CACxD,KAAK,CACM,QAAO,EAAE,KAAK,EAAE,OAAO,kBAAkB,EAAE,IAAI;AAC5D,KAAE,OAAO,OAAO,mBAAmB,CACjC,MAAM,GAAG,OAAO,mBAAmB,gBAAgB,aAAa,CAAC,CACjE,KAAK;AACP,KAAE,OAAO,OAAO,UAAU,CAAC,MAAM,GAAG,OAAO,UAAU,gBAAgB,aAAa,CAAC,CAAC,KAAK;AACzF,UAAO,EAAE,KAAK,EAAE,IAAI,MAAM,CAAC;;GAE3B;AAEF,QAAO;;;;;;;;;;;;;;ACz6ER,IAAI,cAAkC;;AAGtC,SAAgB,WAAwB;AACvC,KAAI,CAAC,YACJ,eAAc,IAAI,YAAY,eAAe,CAAC;AAE/C,QAAO;;;AAIR,SAAgB,aAAmB;AAClC,cAAa,OAAO;AACpB,eAAc;;AAgCf,SAAgB,UAAU,MAAmB;CAC5C,MAAM,eAAe,MAAM,gBAAgB;CAC3C,MAAM,UAAU,MAAM,WAAW;CACjC,MAAM,WAAW,MAAM,YAAY;CACnC,MAAM,uBAAuB,MAAM,+BAA+B;CAClE,MAAM,MAAM,IAAI,MAAM;AAGtB,KAAI,IAAI,KAAK,kBAAkB,CAAC;AAChC,KAAI,IAAI,KAAK,aAAa,CAAC;AAG3B,KAAI,MAAM,KAAK,YAAY,aAAa,CAAC;AACzC,KAAI,MAAM,KAAK,aAAa,aAAa,CAAC;AAC1C,KAAI,MACH,KACA,qBAAqB;EACpB,UAAU;EACV,kBAAkB;EAClB,mBAAmB;EACnB,CAAC,CACF;AACD,KAAI,MAAM,KAAK,aAAa,EAAE,kBAAkB,SAAS,CAAC,CAAC;AAC3D,KAAI,MAAM,KAAK,gBAAgB,cAAc,QAAQ,CAAC;AACtD,KAAI,MAAM,KAAK,WAAW,cAAc,qBAAqB,CAAC;CAI9D,MAAM,aACL,QAAQ,IAAI,6BAA6B,KAAK,OAAO,KAAK,WAAW,KAAK,YAAY;AAEvF,KAAI,IACH,aACA,YAAY;EACX,MAAM;EACN,qBAAqB,SAAS,KAAK,QAAQ,aAAa,GAAG;EAC3D,CAAC,CACF;CAGD,MAAM,YAAY,KAAK,YAAY,aAAa;AAChD,KAAI,CAAC,WAAW,UAAU,CACzB,OAAM,IAAI,MACT,4BAA4B,UAAU,qEACtC;CAEF,MAAM,YAAY,aAAa,WAAW,QAAQ;AAClD,KAAI,IAAI,MAAM,MAAM;AACnB,MAAI,EAAE,IAAI,KAAK,WAAW,QAAQ,CACjC,QAAO,EAAE,KAAK,EAAE,OAAO,aAAa,EAAE,IAAI;AAE3C,SAAO,EAAE,KAAK,UAAU;GACvB;AAEF,QAAO;;;;;;;;;;;;AAaR,SAAgB,cAAc,MAAmB;CAChD,MAAM,eAAe,MAAM,gBAAgB;CAC3C,MAAM,mBAAmB,MAAM,wBAAwB,EAAE;CACzD,MAAM,cAAc,iBAAiB,WAAW,kCAAkC;CAClF,MAAM,YAAY,KAAK,IAAI,GAAG,KAAK,MAAM,iBAAiB,aAAa,IAAI,CAAC;CAC5E,MAAM,gBAAgB,KAAK,IAAI,GAAG,KAAK,MAAM,iBAAiB,iBAAiB,GAAG,CAAC;CACnF,MAAM,MAAM,IAAI,MAAM;AACtB,KAAI,MACH,KACA,mBAAmB,cAAc,EAChC,gBAAgB;EACf,SAAS;EACT;EACA;EACA,0BAA0B,KAAK,IAC9B,GACA,KAAK,MAAM,iBAAiB,4BAA4B,KAAK,IAAI,IAAI,UAAU,CAAC,CAChF;EACD,8BAA8B,KAAK,IAClC,GACA,KAAK,MAAM,iBAAiB,gCAAgC,KAAK,IAAI,IAAI,cAAc,CAAC,CACxF;EACD,EACD,CAAC,CACF;AAGD,KAAI,IAAI,MAAM,MAAM,EAAE,KAAK,EAAE,OAAO,aAAa,EAAE,IAAI,CAAC;AAExD,QAAO"}