@codemem/server 0.33.0-alpha.1 → 0.33.0-alpha.3
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 +5 -1
- package/dist/index.js.map +1 -1
- package/dist/routes/sync.d.ts.map +1 -1
- package/package.json +2 -2
- package/static/app.js +95 -40
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 REMOVED_CONFIG_KEYS = new Set<string>([\"observer_rich_openai_use_responses\"]);\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_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_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 withoutRemovedConfigKeys(configData: ConfigData): ConfigData {\n\tconst next = { ...configData };\n\tfor (const key of REMOVED_CONFIG_KEYS) {\n\t\tdelete next[key];\n\t}\n\treturn next;\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\") {\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 = withoutRemovedConfigKeys(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 = withoutRemovedConfigKeys(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 { MemoryFilters, MemoryStore } from \"@codemem/core\";\nimport {\n\tbuildFilterClausesWithContext,\n\tcanonicalMemoryKind,\n\tfromJson,\n\tisSummaryLikeMemory as isCoreSummaryLikeMemory,\n\tparseStrictInteger,\n\tschema,\n} from \"@codemem/core\";\nimport { eq, inArray } 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 buildViewerMemoryFilters(store: MemoryStore, filters?: MemoryFilters | null) {\n\treturn buildFilterClausesWithContext(filters, {\n\t\tactorId: store.actorId,\n\t\tdeviceId: store.deviceId,\n\t\tenforceScopeVisibility: true,\n\t});\n}\n\nfunction countVisibleMemoryRows(store: MemoryStore, filters?: MemoryFilters | null): number {\n\tconst filterResult = buildViewerMemoryFilters(store, filters);\n\tconst clauses = [\"memory_items.active = 1\", ...filterResult.clauses];\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\tconst row = store.db\n\t\t.prepare(`SELECT COUNT(*) AS total FROM ${from} WHERE ${clauses.join(\" AND \")}`)\n\t\t.get(...filterResult.params) as Record<string, unknown> | undefined;\n\treturn Number(row?.total ?? 0);\n}\n\nfunction summaryLikeSqlPredicate(): string {\n\treturn `(\n\t\tLOWER(TRIM(COALESCE(memory_items.kind, ''))) = 'session_summary'\n\t\tOR (\n\t\t\tjson_valid(COALESCE(memory_items.metadata_json, ''))\n\t\t\tAND (\n\t\t\t\tCOALESCE(json_extract(memory_items.metadata_json, '$.is_summary') = 1, 0)\n\t\t\t\tOR LOWER(TRIM(COALESCE(json_extract(memory_items.metadata_json, '$.source'), ''))) = 'observer_summary'\n\t\t\t)\n\t\t)\n\t)`;\n}\n\nfunction countVisibleObservationRows(store: MemoryStore, filters?: MemoryFilters | null): number {\n\tconst filterResult = buildViewerMemoryFilters(store, filters);\n\tconst clauses = [\n\t\t\"memory_items.active = 1\",\n\t\t`NOT ${summaryLikeSqlPredicate()}`,\n\t\t...filterResult.clauses,\n\t];\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\tconst row = store.db\n\t\t.prepare(`SELECT COUNT(*) AS total FROM ${from} WHERE ${clauses.join(\" AND \")}`)\n\t\t.get(...filterResult.params) as Record<string, unknown> | undefined;\n\treturn Number(row?.total ?? 0);\n}\n\nfunction sessionAllowsArtifactAccess(store: MemoryStore, sessionId: number): boolean {\n\tconst visibleCount = countVisibleMemoryRows(store, { session_id: sessionId });\n\tif (visibleCount === 0) return false;\n\tconst row = store.db\n\t\t.prepare(\n\t\t\t`SELECT COUNT(*) AS total FROM memory_items\n\t\t\t WHERE session_id = ? AND active = 1`,\n\t\t)\n\t\t.get(sessionId) as Record<string, unknown> | undefined;\n\treturn visibleCount === Number(row?.total ?? 0);\n}\n\nfunction countVisiblePromptRows(store: MemoryStore, project?: string | null): number {\n\tconst filterResult = buildViewerMemoryFilters(store, null);\n\tconst clauses = [\n\t\t\"user_prompts.session_id IS NOT NULL\",\n\t\t`EXISTS (\n\t\t\tSELECT 1 FROM memory_items\n\t\t\tWHERE memory_items.session_id = user_prompts.session_id\n\t\t\t AND memory_items.active = 1\n\t\t\t AND ${filterResult.clauses.join(\" AND \")}\n\t\t)`,\n\t];\n\tconst params: unknown[] = [...filterResult.params];\n\tif (project) {\n\t\tclauses.unshift(\"user_prompts.project = ?\");\n\t\tparams.unshift(project);\n\t}\n\tconst row = store.db\n\t\t.prepare(`SELECT COUNT(*) AS total FROM user_prompts WHERE ${clauses.join(\" AND \")}`)\n\t\t.get(...params) as Record<string, unknown> | undefined;\n\treturn Number(row?.total ?? 0);\n}\n\nfunction countVisibleArtifactRows(store: MemoryStore, project?: string | null): number {\n\tconst filterResult = buildViewerMemoryFilters(store, null);\n\tconst clauses = [\n\t\t`EXISTS (\n\t\t\tSELECT 1 FROM memory_items\n\t\t\tWHERE memory_items.session_id = artifacts.session_id\n\t\t\t AND memory_items.active = 1\n\t\t\t AND ${filterResult.clauses.join(\" AND \")}\n\t\t)`,\n\t];\n\tconst params: unknown[] = [...filterResult.params];\n\tconst from = project\n\t\t? \"artifacts JOIN sessions ON sessions.id = artifacts.session_id\"\n\t\t: \"artifacts\";\n\tif (project) {\n\t\tclauses.unshift(\"sessions.project = ?\");\n\t\tparams.unshift(project);\n\t}\n\tconst row = store.db\n\t\t.prepare(`SELECT COUNT(*) AS total FROM ${from} WHERE ${clauses.join(\" AND \")}`)\n\t\t.get(...params) as Record<string, unknown> | undefined;\n\treturn Number(row?.total ?? 0);\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: MemoryFilters = {};\n\tif (options.project) filters.project = options.project;\n\tif (options.scope) filters.ownership_scope = options.scope;\n\n\tconst filterResult = buildViewerMemoryFilters(store, filters);\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 filterResult = buildViewerMemoryFilters(store, null);\n\t\t\tconst clauses = [\n\t\t\t\t\"memory_items.session_id = sessions.id\",\n\t\t\t\t\"memory_items.active = 1\",\n\t\t\t\t...filterResult.clauses,\n\t\t\t];\n\t\t\tconst rows = store.db\n\t\t\t\t.prepare(\n\t\t\t\t\t`SELECT sessions.* FROM sessions\n\t\t\t\t\t WHERE EXISTS (SELECT 1 FROM memory_items WHERE ${clauses.join(\" AND \")})\n\t\t\t\t\t ORDER BY sessions.started_at DESC\n\t\t\t\t\t LIMIT ?`,\n\t\t\t\t)\n\t\t\t\t.all(...filterResult.params, limit) as Record<string, unknown>[];\n\t\t\tconst items = rows.map((row) => ({\n\t\t\t\t...row,\n\t\t\t\tmetadata_json: fromJson((row.metadata_json as string | null | undefined) ?? null),\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 filterResult = buildViewerMemoryFilters(store, null);\n\t\t\tconst clauses = [\n\t\t\t\t\"memory_items.session_id = sessions.id\",\n\t\t\t\t\"memory_items.active = 1\",\n\t\t\t\t\"sessions.project IS NOT NULL\",\n\t\t\t\t...filterResult.clauses,\n\t\t\t];\n\t\t\tconst rows = store.db\n\t\t\t\t.prepare(\n\t\t\t\t\t`SELECT DISTINCT sessions.project AS project FROM sessions\n\t\t\t\t\t JOIN memory_items ON memory_items.session_id = sessions.id\n\t\t\t\t\t WHERE ${clauses.join(\" AND \")}`,\n\t\t\t\t)\n\t\t\t\t.all(...filterResult.params) as Record<string, unknown>[];\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\tlet prompts: number;\n\t\t\tlet artifacts: number;\n\t\t\tlet memories: number;\n\t\t\tlet observations: number;\n\t\t\tif (project) {\n\t\t\t\tprompts = countVisiblePromptRows(store, project);\n\t\t\t\tartifacts = countVisibleArtifactRows(store, project);\n\t\t\t\tmemories = countVisibleMemoryRows(store, { project });\n\t\t\t\tobservations = countVisibleObservationRows(store, { project });\n\t\t\t} else {\n\t\t\t\tprompts = countVisiblePromptRows(store);\n\t\t\t\tartifacts = countVisibleArtifactRows(store);\n\t\t\t\tmemories = countVisibleMemoryRows(store);\n\t\t\t\tobservations = countVisibleObservationRows(store);\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: MemoryFilters = {};\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\tif (!sessionAllowsArtifactAccess(store, sessionId)) {\n\t\t\t\treturn c.json({ error: \"session not found\" }, 404);\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\tif (!store.get(memoryId)) {\n\t\t\treturn c.json({ error: \"memory not found\" }, 404);\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/project\n\tapp.post(\"/api/memories/project\", 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 project = String(body.project ?? \"\").trim();\n\t\tif (!project) {\n\t\t\treturn c.json({ error: \"project must be a non-empty string\" }, 400);\n\t\t}\n\t\tif (!store.get(memoryId)) {\n\t\t\treturn c.json({ error: \"memory not found\" }, 404);\n\t\t}\n\t\ttry {\n\t\t\tconst result = store.moveMemoryProject(memoryId, project);\n\t\t\treturn c.json(result);\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\t\tif (!store.get(memoryId)) {\n\t\t\treturn c.json({ error: \"memory not found\" }, 404);\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 {\n\tbuildFilterClausesWithContext,\n\tlistMaintenanceJobs,\n\ttype MemoryStore,\n\tVERSION,\n} 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\nconst MEMORY_ID_METADATA_KEYS = [\"pack_item_ids\", \"added_ids\", \"removed_ids\", \"retained_ids\"];\n\ntype UsageRow = {\n\tid: number;\n\tsession_id: number | null;\n\tevent: string;\n\ttokens_read: number;\n\ttokens_written: number;\n\ttokens_saved: number;\n\tcreated_at: string;\n\tmetadata_json: Record<string, unknown> | null;\n};\n\ntype UsageVisibility = {\n\tvisibleMemoryIds: Set<number>;\n\tvisibleSessionIds: Set<number>;\n};\n\nfunction toUsageRow(\n\trow: Record<string, unknown>,\n\tmetadata: Record<string, unknown> | null,\n): UsageRow {\n\treturn {\n\t\tid: Number(row.id ?? 0),\n\t\tsession_id: row.session_id == null ? null : Number(row.session_id),\n\t\tevent: String(row.event ?? \"pack\"),\n\t\ttokens_read: Number(row.tokens_read ?? 0),\n\t\ttokens_written: Number(row.tokens_written ?? 0),\n\t\ttokens_saved: Number(row.tokens_saved ?? 0),\n\t\tcreated_at: String(row.created_at ?? \"\"),\n\t\tmetadata_json: metadata,\n\t};\n}\n\nfunction metadataMemoryIds(value: unknown): number[] {\n\tif (!Array.isArray(value)) return [];\n\treturn value\n\t\t.map((item) => (typeof item === \"number\" ? item : Number(item)))\n\t\t.filter((item) => Number.isInteger(item) && item > 0);\n}\n\nfunction chunkNumbers(values: number[], chunkSize = 500): number[][] {\n\tconst chunks: number[][] = [];\n\tfor (let start = 0; start < values.length; start += chunkSize) {\n\t\tchunks.push(values.slice(start, start + chunkSize));\n\t}\n\treturn chunks;\n}\n\nfunction visibleMemoryIdSet(store: MemoryStore, memoryIds: Set<number>): Set<number> {\n\tif (memoryIds.size === 0) return new Set();\n\tconst filterResult = buildFilterClausesWithContext(null, {\n\t\tactorId: store.actorId,\n\t\tdeviceId: store.deviceId,\n\t\tenforceScopeVisibility: true,\n\t});\n\tconst visibleIds = new Set<number>();\n\tfor (const chunk of chunkNumbers([...memoryIds])) {\n\t\tconst placeholders = chunk.map(() => \"?\").join(\", \");\n\t\tconst clauses = [\n\t\t\t\"memory_items.active = 1\",\n\t\t\t`memory_items.id IN (${placeholders})`,\n\t\t\t...filterResult.clauses,\n\t\t];\n\t\tconst rows = store.db\n\t\t\t.prepare(`SELECT memory_items.id FROM memory_items WHERE ${clauses.join(\" AND \")}`)\n\t\t\t.all(...chunk, ...filterResult.params) as Array<{ id: number }>;\n\t\tfor (const row of rows) visibleIds.add(Number(row.id));\n\t}\n\treturn visibleIds;\n}\n\nfunction visibleSessionIdSet(store: MemoryStore, sessionIds: Set<number>): Set<number> {\n\tif (sessionIds.size === 0) return new Set();\n\tconst filterResult = buildFilterClausesWithContext(null, {\n\t\tactorId: store.actorId,\n\t\tdeviceId: store.deviceId,\n\t\tenforceScopeVisibility: true,\n\t});\n\tconst visibleIds = new Set<number>();\n\tfor (const chunk of chunkNumbers([...sessionIds])) {\n\t\tconst placeholders = chunk.map(() => \"?\").join(\", \");\n\t\tconst clauses = [\n\t\t\t\"memory_items.active = 1\",\n\t\t\t`memory_items.session_id IN (${placeholders})`,\n\t\t\t...filterResult.clauses,\n\t\t];\n\t\tconst rows = store.db\n\t\t\t.prepare(\n\t\t\t\t`SELECT DISTINCT memory_items.session_id AS session_id\n\t\t\t\t FROM memory_items\n\t\t\t\t WHERE ${clauses.join(\" AND \")}`,\n\t\t\t)\n\t\t\t.all(...chunk, ...filterResult.params) as Array<{ session_id: number | null }>;\n\t\tfor (const row of rows) {\n\t\t\tif (typeof row.session_id === \"number\") visibleIds.add(row.session_id);\n\t\t}\n\t}\n\treturn visibleIds;\n}\n\nfunction buildUsageVisibility(store: MemoryStore, rows: UsageRow[]): UsageVisibility {\n\tconst memoryIds = new Set<number>();\n\tconst sessionIds = new Set<number>();\n\tfor (const row of rows) {\n\t\tif (typeof row.session_id === \"number\") sessionIds.add(row.session_id);\n\t\tfor (const key of MEMORY_ID_METADATA_KEYS) {\n\t\t\tfor (const memoryId of metadataMemoryIds(row.metadata_json?.[key])) {\n\t\t\t\tmemoryIds.add(memoryId);\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tvisibleMemoryIds: visibleMemoryIdSet(store, memoryIds),\n\t\tvisibleSessionIds: visibleSessionIdSet(store, sessionIds),\n\t};\n}\n\nfunction usageRowVisible(row: UsageRow, visibility: UsageVisibility): boolean {\n\tconst rowSessionVisible =\n\t\trow.session_id == null || visibility.visibleSessionIds.has(row.session_id);\n\tconst packItemIds = row.metadata_json?.pack_item_ids;\n\tif (Array.isArray(packItemIds)) {\n\t\tif (packItemIds.length === 0) {\n\t\t\treturn row.session_id != null && visibility.visibleSessionIds.has(row.session_id);\n\t\t}\n\t\treturn (\n\t\t\trowSessionVisible &&\n\t\t\tmetadataMemoryIds(packItemIds).some((memoryId) => visibility.visibleMemoryIds.has(memoryId))\n\t\t);\n\t}\n\treturn row.session_id != null && visibility.visibleSessionIds.has(row.session_id);\n}\n\nfunction sanitizePackUsageMetadata(\n\tmetadata: Record<string, unknown> | null,\n\tvisibility: UsageVisibility,\n): Record<string, unknown> | null {\n\tif (!metadata) return null;\n\tconst sanitized = { ...metadata };\n\tfor (const key of MEMORY_ID_METADATA_KEYS) {\n\t\tif (Array.isArray(sanitized[key])) {\n\t\t\tsanitized[key] = metadataMemoryIds(sanitized[key]).filter((memoryId) =>\n\t\t\t\tvisibility.visibleMemoryIds.has(memoryId),\n\t\t\t);\n\t\t}\n\t}\n\treturn sanitized;\n}\n\nfunction summarizeUsageEvents(rows: UsageRow[]): Record<string, unknown>[] {\n\tconst byEvent = new Map<\n\t\tstring,\n\t\t{\n\t\t\tevent: string;\n\t\t\ttotal_tokens_read: number;\n\t\t\ttotal_tokens_written: number;\n\t\t\ttotal_tokens_saved: number;\n\t\t\tcount: number;\n\t\t}\n\t>();\n\tfor (const row of rows) {\n\t\tconst summary = byEvent.get(row.event) ?? {\n\t\t\tevent: row.event,\n\t\t\ttotal_tokens_read: 0,\n\t\t\ttotal_tokens_written: 0,\n\t\t\ttotal_tokens_saved: 0,\n\t\t\tcount: 0,\n\t\t};\n\t\tsummary.total_tokens_read += row.tokens_read;\n\t\tsummary.total_tokens_written += row.tokens_written;\n\t\tsummary.total_tokens_saved += row.tokens_saved;\n\t\tsummary.count += 1;\n\t\tbyEvent.set(row.event, summary);\n\t}\n\treturn [...byEvent.values()].sort((a, b) => a.event.localeCompare(b.event));\n}\n\nfunction totalUsageEvents(rows: UsageRow[]): Record<string, unknown> {\n\treturn rows.reduce(\n\t\t(acc, row) => ({\n\t\t\ttokens_read: Number(acc.tokens_read) + row.tokens_read,\n\t\t\ttokens_written: Number(acc.tokens_written) + row.tokens_written,\n\t\t\ttokens_saved: Number(acc.tokens_saved) + row.tokens_saved,\n\t\t\tcount: Number(acc.count) + 1,\n\t\t}),\n\t\t{ tokens_read: 0, tokens_written: 0, tokens_saved: 0, count: 0 } as Record<string, unknown>,\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\t// Keep completed jobs visible in /api/stats for a short window after\n\t// finished_at so the health UI has a chance to render success confirmation\n\t// for fast-completing backfills (often <1s). Failed jobs stay indefinitely.\n\tconst RECENTLY_COMPLETED_WINDOW_MS = 120_000;\n\n\tapp.get(\"/api/stats\", (c) => {\n\t\tconst store = getStore();\n\t\tconst jobs = listMaintenanceJobs(store.db);\n\t\tconst now = Date.now();\n\t\tconst surfacedJobs = sortActiveMaintenanceJobs(\n\t\t\tjobs.filter((job) => {\n\t\t\t\tif (job.status === \"pending\" || job.status === \"running\" || job.status === \"failed\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (job.status === \"completed\" && job.finished_at) {\n\t\t\t\t\tconst finished = Date.parse(job.finished_at);\n\t\t\t\t\tif (Number.isFinite(finished) && now - finished <= RECENTLY_COMPLETED_WINDOW_MS) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\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\tfinished_at: job.finished_at,\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: surfacedJobs,\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 loadUsageRows = (project?: string | null): UsageRow[] => {\n\t\t\t\tconst rows = project\n\t\t\t\t\t? (store.db\n\t\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t\t`SELECT usage_events.id, usage_events.session_id, usage_events.event,\n\t\t\t\t\t\t\t\t\tusage_events.tokens_read, usage_events.tokens_written, usage_events.tokens_saved,\n\t\t\t\t\t\t\t\t\tusage_events.created_at, usage_events.metadata_json\n\t\t\t\t\t\t\t\t FROM usage_events\n\t\t\t\t\t\t\t\t JOIN sessions ON sessions.id = usage_events.session_id\n\t\t\t\t\t\t\t\t WHERE sessions.project = ?\n\t\t\t\t\t\t\t\t ORDER BY usage_events.created_at DESC`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.all(project) as Record<string, unknown>[])\n\t\t\t\t\t: (store.db\n\t\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t\t`SELECT id, session_id, event, tokens_read, tokens_written, tokens_saved,\n\t\t\t\t\t\t\t\t\tcreated_at, metadata_json\n\t\t\t\t\t\t\t\t FROM usage_events\n\t\t\t\t\t\t\t\t ORDER BY created_at DESC`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.all() as Record<string, unknown>[]);\n\t\t\t\treturn rows.map((row) => toUsageRow(row, parseMetadataJson(row.metadata_json)));\n\t\t\t};\n\t\t\tconst loadedGlobalRows = loadUsageRows();\n\t\t\tconst globalVisibility = buildUsageVisibility(store, loadedGlobalRows);\n\t\t\tconst globalRows = loadedGlobalRows.filter((row) => usageRowVisible(row, globalVisibility));\n\t\t\tconst loadedFilteredRows = projectFilter ? loadUsageRows(projectFilter) : null;\n\t\t\tconst filteredVisibility = loadedFilteredRows\n\t\t\t\t? buildUsageVisibility(store, loadedFilteredRows)\n\t\t\t\t: null;\n\t\t\tconst filteredRows = loadedFilteredRows\n\t\t\t\t? loadedFilteredRows.filter((row) =>\n\t\t\t\t\t\tusageRowVisible(row, filteredVisibility ?? globalVisibility),\n\t\t\t\t\t)\n\t\t\t\t: null;\n\t\t\tconst eventsGlobal = summarizeUsageEvents(globalRows);\n\t\t\tconst totalsGlobal = totalUsageEvents(globalRows);\n\t\t\tconst eventsFiltered = filteredRows ? summarizeUsageEvents(filteredRows) : null;\n\t\t\tconst totalsFiltered = filteredRows ? totalUsageEvents(filteredRows) : null;\n\t\t\tconst recentVisibility = filteredVisibility ?? globalVisibility;\n\t\t\tconst recentPacks = (filteredRows ?? globalRows)\n\t\t\t\t.filter((row) => row.event === \"pack\")\n\t\t\t\t.slice(0, 10)\n\t\t\t\t.map((row) => ({\n\t\t\t\t\t...row,\n\t\t\t\t\tmetadata_json: sanitizePackUsageMetadata(row.metadata_json, recentVisibility),\n\t\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 { networkInterfaces } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type {\n\tCoordinatorBootstrapGrantVerification,\n\tCoordinatorScope,\n\tCoordinatorScopeMembership,\n\tMaintenanceJobSnapshot,\n\tMemoryStore,\n\tProjectScopeGuardrailWarning,\n\tReplicationOp,\n\tSemanticIndexDiagnostics,\n} from \"@codemem/core\";\nimport {\n\taddSyncScopeToBoundary,\n\tanalyzeProjectScopeMappingChangeGuardrails,\n\tapplyReplicationOps,\n\tbuildBaseUrl,\n\tcanonicalWorkspaceIdentity,\n\tcleanupNonces,\n\tcoordinatorArchiveGroupAction,\n\tcoordinatorCreateGroupAction,\n\tcoordinatorCreateInviteAction,\n\tcoordinatorCreateScopeAction,\n\tcoordinatorDisableDeviceAction,\n\tcoordinatorEnableDeviceAction,\n\tcoordinatorGrantScopeMembershipAction,\n\tcoordinatorImportInviteAction,\n\tcoordinatorListBootstrapGrantsAction,\n\tcoordinatorListDevicesAction,\n\tcoordinatorListGroupsAction,\n\tcoordinatorListJoinRequestsAction,\n\tcoordinatorListScopeMembershipsAction,\n\tcoordinatorListScopesAction,\n\tcoordinatorRemoveDeviceAction,\n\tcoordinatorRenameDeviceAction,\n\tcoordinatorRenameGroupAction,\n\tcoordinatorReviewJoinRequestAction,\n\tcoordinatorRevokeBootstrapGrantAction,\n\tcoordinatorRevokeScopeMembershipAction,\n\tcoordinatorStatusSnapshot,\n\tcoordinatorUnarchiveGroupAction,\n\tcoordinatorUpdateScopeAction,\n\tcreateCoordinatorReciprocalApproval,\n\tDEFAULT_TIME_WINDOW_S,\n\tdefaultSpaceScopeIdForGroup,\n\tdeleteProjectScopeSettingsMapping,\n\tensureDeviceIdentity,\n\textractReplicationOps,\n\ttype FilterReplicationSkipped,\n\tfilterReplicationOpsForSyncWithStatus,\n\tfingerprintPublicKey,\n\tformatHostPort,\n\tgetCoordinatorGroupPreference,\n\tgetSemanticIndexDiagnostics,\n\tgetSyncResetState,\n\ttype InboundScopeRejectionPeerSummary,\n\tisScopedSyncCapability,\n\tLEGACY_SHARED_REVIEW_SCOPE_ID,\n\tLOCAL_DEFAULT_SCOPE_ID,\n\tLOCAL_SYNC_CAPABILITY,\n\tlistAuthorizedScopesForPeer,\n\tlistCoordinatorJoinRequests,\n\tlistInboundScopeRejections,\n\tlistMaintenanceJobs,\n\tlistPerPeerScopeSyncState,\n\tlistProjectScopeCandidates,\n\tlistProjectScopeInventory,\n\tlistProjectScopeSettingsMappings,\n\tlistSharingDomainSettingsScopes,\n\tloadMemorySnapshotPageForPeer,\n\tloadReplicationOpsForPeer,\n\tlookupCoordinatorPeers,\n\tmergeAddresses,\n\tnegotiateSyncCapability,\n\tnormalizeAddress,\n\tnormalizeSyncCapability,\n\tparseSyncScopeRequest,\n\tpersonalScopeGrantStatusForPeer,\n\treadCodememConfigFile,\n\treadCoordinatorSyncConfig,\n\treassignProjectScopeInventoryProject,\n\trecordNonce,\n\trejectInboundScopeFailures,\n\trequestJson,\n\trunSyncPass,\n\tSYNC_CAPABILITY_HEADER,\n\tSYNC_SCOPE_QUERY_PARAM,\n\tschema,\n\tsummarizeInboundScopeRejections,\n\tsyncScopeResetRequiredPayload,\n\tupdatePeerAddresses,\n\tupsertCoordinatorGroupPreference,\n\tupsertProjectScopeSettingsMapping,\n\tverifySignature,\n\twriteCodememConfigFile,\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\ntype SafeSkippedSyncDetail = Pick<\n\tFilterReplicationSkipped,\n\t\"reason\" | \"skipped_count\" | \"scope_id\" | \"project\" | \"visibility\"\n>;\n\nfunction safeSkippedSyncDetail(\n\tdetail: FilterReplicationSkipped | null | undefined,\n): SafeSkippedSyncDetail | null {\n\tif (!detail) return null;\n\treturn {\n\t\treason: detail.reason,\n\t\tskipped_count: detail.skipped_count,\n\t\tscope_id: detail.scope_id ?? null,\n\t\tproject: detail.project ?? null,\n\t\tvisibility: detail.visibility ?? null,\n\t};\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\n/**\n * Attempt to decode a pasted string as a device-pairing payload.\n *\n * Returns:\n * - `{ kind: \"pair\", ... }` when the payload base64-decodes to JSON with\n * the expected pairing shape AND the fingerprint matches the public\n * key.\n * - `{ kind: \"invalid-pair\", error }` when the payload looked like a\n * pairing payload but failed validation — the caller should 400 this\n * rather than falling back to coordinator-invite handling.\n * - `null` when the string is not a pairing payload at all.\n */\nfunction tryParsePairingPayload(value: string):\n\t| {\n\t\t\tkind: \"pair\";\n\t\t\tdevice_id: string;\n\t\t\tfingerprint: string;\n\t\t\tpublic_key: string;\n\t\t\taddresses: string[];\n\t }\n\t| { kind: \"invalid-pair\"; error: string }\n\t| null {\n\t// Accept both shapes the CLI can emit:\n\t// - raw JSON (`codemem sync pair --payload-only`)\n\t// - base64-encoded JSON (the inner blob inside the shell pipe wrapper)\n\tlet parsed: Record<string, unknown>;\n\tif (value.trimStart().startsWith(\"{\")) {\n\t\ttry {\n\t\t\tparsed = JSON.parse(value) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t} else {\n\t\tlet decoded: string;\n\t\ttry {\n\t\t\tdecoded = Buffer.from(value, \"base64\").toString(\"utf8\");\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t\tif (!decoded?.trimStart().startsWith(\"{\")) return null;\n\t\ttry {\n\t\t\tparsed = JSON.parse(decoded) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\tconst deviceId = String(parsed.device_id ?? \"\").trim();\n\tconst fingerprint = String(parsed.fingerprint ?? \"\").trim();\n\tconst publicKey = String(parsed.public_key ?? \"\").trim();\n\t// If the JSON doesn't carry any of the pairing discriminators, treat\n\t// it as a different kind of payload (e.g. a coordinator invite happened\n\t// to be JSON-encoded directly). Let the caller keep trying.\n\tif (!deviceId && !fingerprint && !publicKey) return null;\n\tconst rawAddresses = Array.isArray(parsed.addresses) ? parsed.addresses : [];\n\tconst addresses = rawAddresses\n\t\t.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0)\n\t\t.map((item) => item.trim());\n\tif (!deviceId || !fingerprint || !publicKey || addresses.length === 0) {\n\t\treturn {\n\t\t\tkind: \"invalid-pair\",\n\t\t\terror: \"Pairing payload missing device_id, fingerprint, public_key, or addresses\",\n\t\t};\n\t}\n\tif (fingerprintPublicKey(publicKey) !== fingerprint) {\n\t\treturn { kind: \"invalid-pair\", error: \"Pairing payload fingerprint mismatch\" };\n\t}\n\treturn {\n\t\tkind: \"pair\",\n\t\tdevice_id: deviceId,\n\t\tfingerprint,\n\t\tpublic_key: publicKey,\n\t\taddresses,\n\t};\n}\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\nasync function ensureDefaultSpaceForTeam(opts: {\n\tstore: MemoryStore;\n\tconfig: ReturnType<typeof readCoordinatorSyncConfig>;\n\tgroupId: string;\n\tdisplayName: string | null;\n}): Promise<{\n\tscope: CoordinatorScope | null;\n\tmembership: CoordinatorScopeMembership | null;\n\tpreferences: ReturnType<typeof upsertCoordinatorGroupPreference>;\n}> {\n\tconst coordinatorId = opts.config.syncCoordinatorUrl || null;\n\tif (!coordinatorId) throw new Error(\"coordinator_not_configured\");\n\tconst scopeId = defaultSpaceScopeIdForGroup(opts.groupId);\n\tconst label = opts.displayName || opts.groupId;\n\tconst existingScopes = await coordinatorListScopesAction({\n\t\tgroupId: opts.groupId,\n\t\tincludeInactive: false,\n\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t});\n\tconst existingScope = existingScopes.find((scope) => scope.scope_id === scopeId) ?? null;\n\tconst scope =\n\t\texistingScope ??\n\t\t(await coordinatorCreateScopeAction({\n\t\t\tgroupId: opts.groupId,\n\t\t\tscopeId,\n\t\t\tlabel,\n\t\t\tkind: \"team_default\",\n\t\t\tauthorityType: \"coordinator\",\n\t\t\tcoordinatorId,\n\t\t\tmembershipEpoch: 1,\n\t\t\tstatus: \"active\",\n\t\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t\t}));\n\tconst [deviceId] = ensureDeviceIdentity(opts.store.db, { keysDir: syncKeysDir() });\n\tconst membership = await coordinatorGrantScopeMembershipAction({\n\t\tgroupId: opts.groupId,\n\t\tscopeId,\n\t\tdeviceId,\n\t\trole: \"admin\",\n\t\tmembershipEpoch: 1,\n\t\tcoordinatorId,\n\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t});\n\tconst preferences = upsertCoordinatorGroupPreference(opts.store.db, {\n\t\tcoordinator_id: coordinatorId,\n\t\tgroup_id: opts.groupId,\n\t\tdefault_space_scope_id: scopeId,\n\t\tauto_grant_default_space_on_join: true,\n\t});\n\treturn { scope, membership, preferences };\n}\n\nasync function maybeGrantDefaultSpaceOnJoin(opts: {\n\tstore: MemoryStore;\n\tconfig: ReturnType<typeof readCoordinatorSyncConfig>;\n\tgroupId: string;\n\tdeviceId: string;\n}): Promise<CoordinatorScopeMembership | null> {\n\tconst coordinatorId = opts.config.syncCoordinatorUrl || null;\n\tif (!coordinatorId) return null;\n\tconst preferences = getCoordinatorGroupPreference(opts.store.db, coordinatorId, opts.groupId);\n\tif (!preferences?.auto_grant_default_space_on_join) return null;\n\tconst scopeId = preferences.default_space_scope_id?.trim();\n\tif (!scopeId) return null;\n\tif (scopeId !== defaultSpaceScopeIdForGroup(opts.groupId)) return null;\n\tconst scopes = await coordinatorListScopesAction({\n\t\tgroupId: opts.groupId,\n\t\tincludeInactive: false,\n\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t});\n\tconst defaultScope = scopes.find((scope) => scope.scope_id === scopeId) ?? null;\n\tif (!defaultScope || defaultScope.kind !== \"team_default\") return null;\n\treturn await coordinatorGrantScopeMembershipAction({\n\t\tgroupId: opts.groupId,\n\t\tscopeId,\n\t\tdeviceId: opts.deviceId,\n\t\trole: \"member\",\n\t\tmembershipEpoch: 1,\n\t\tcoordinatorId,\n\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t});\n}\n\nfunction removeConfiguredCoordinatorGroup(groupId: string): string[] {\n\tconst targetGroup = groupId.trim();\n\tif (!targetGroup) return [];\n\tconst config = readCodememConfigFile();\n\tconst rawGroups = config.sync_coordinator_groups;\n\tconst groups = Array.isArray(rawGroups)\n\t\t? rawGroups.map((group) => String(group).trim()).filter(Boolean)\n\t\t: typeof rawGroups === \"string\"\n\t\t\t? rawGroups\n\t\t\t\t\t.split(\",\")\n\t\t\t\t\t.map((group) => group.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t: typeof config.sync_coordinator_group === \"string\" && config.sync_coordinator_group.trim()\n\t\t\t\t? [config.sync_coordinator_group.trim()]\n\t\t\t\t: [];\n\tconst nextGroups = groups.filter((group) => group !== targetGroup);\n\tif (nextGroups.length === groups.length) return groups;\n\tconfig.sync_coordinator_groups = nextGroups;\n\tif (nextGroups.length) config.sync_coordinator_group = nextGroups[0];\n\telse delete config.sync_coordinator_group;\n\twriteCodememConfigFile(config);\n\treturn nextGroups;\n}\n\nfunction coordinatorAdminUnavailable(status: ReturnType<typeof coordinatorAdminStatusPayload>): {\n\tbody: Record<string, unknown>;\n\thttpStatus: 400;\n} | null {\n\tif (status.readiness === \"not_configured\") {\n\t\treturn { body: { error: \"coordinator_not_configured\", status }, httpStatus: 400 };\n\t}\n\tif (!status.has_admin_secret) {\n\t\treturn { body: { error: \"coordinator_admin_secret_missing\", status }, httpStatus: 400 };\n\t}\n\treturn null;\n}\n\nasync function parseViewerJsonBody(\n\tc: Context,\n\toptions: { allowEmpty?: boolean } = {},\n): Promise<Record<string, unknown> | null> {\n\tconst raw = await c.req.text();\n\tif (!raw.trim()) return options.allowEmpty ? {} : null;\n\ttry {\n\t\tconst parsed = JSON.parse(raw) 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 optionalViewerString(body: Record<string, unknown>, key: string): string | null {\n\tconst value = body[key];\n\tif (value == null) return null;\n\treturn String(value).trim() || null;\n}\n\nfunction optionalViewerStrictString(body: Record<string, unknown>, key: string): string | null {\n\tconst value = body[key];\n\tif (value == null) return null;\n\tif (typeof value !== \"string\") throw new Error(`${key} must be string`);\n\treturn value.trim() || null;\n}\n\nfunction optionalViewerStringList(body: Record<string, unknown>, key: string): string[] {\n\tconst value = body[key];\n\tif (value == null) return [];\n\tif (!Array.isArray(value)) throw new Error(`${key} must be an array of strings`);\n\treturn [\n\t\t...new Set(\n\t\t\tvalue\n\t\t\t\t.map((item) => {\n\t\t\t\t\tif (typeof item !== \"string\") throw new Error(`${key} must be an array of strings`);\n\t\t\t\t\treturn item.trim();\n\t\t\t\t})\n\t\t\t\t.filter(Boolean),\n\t\t),\n\t];\n}\n\nfunction optionalViewerNumber(body: Record<string, unknown>, key: string): number | null {\n\tconst value = body[key];\n\tif (value == null || value === \"\") return null;\n\tconst number = typeof value === \"number\" ? value : Number(value);\n\treturn Number.isFinite(number) ? Math.trunc(number) : Number.NaN;\n}\n\nfunction optionalViewerInteger(body: Record<string, unknown>, key: string): number | null {\n\tconst value = body[key];\n\tif (value == null || value === \"\") return null;\n\tconst number = typeof value === \"number\" ? value : Number(value);\n\treturn Number.isInteger(number) ? number : Number.NaN;\n}\n\nfunction missingGuardrailConfirmations(\n\twarnings: ProjectScopeGuardrailWarning[],\n\tconfirmedTokens: string[],\n): ProjectScopeGuardrailWarning[] {\n\tconst confirmed = new Set(confirmedTokens);\n\treturn warnings.filter(\n\t\t(warning) =>\n\t\t\twarning.requires_confirmation &&\n\t\t\t(!warning.confirmation_token || !confirmed.has(warning.confirmation_token)),\n\t);\n}\n\nfunction parseViewerProjectMappingInput(body: Record<string, unknown>) {\n\tconst id = optionalViewerInteger(body, \"id\");\n\tconst priority = optionalViewerInteger(body, \"priority\");\n\tif (Number.isNaN(id)) throw new Error(\"id must be an integer\");\n\tif (Number.isNaN(priority)) throw new Error(\"priority must be an integer\");\n\treturn {\n\t\tid,\n\t\tworkspace_identity: optionalViewerStrictString(body, \"workspace_identity\"),\n\t\tproject_pattern: optionalViewerStrictString(body, \"project_pattern\"),\n\t\tscope_id: optionalViewerStrictString(body, \"scope_id\") ?? \"\",\n\t\tpriority,\n\t\tsource: optionalViewerStrictString(body, \"source\") ?? \"user\",\n\t};\n}\n\nfunction coordinatorAdminMutationStatus(message: string): 400 | 404 | 409 | 502 {\n\tif (\n\t\tmessage.includes(\"scope_not_found\") ||\n\t\tmessage.includes(\"membership_not_found\") ||\n\t\tmessage.includes(\"group_not_found\") ||\n\t\tmessage.includes(\"Group not found\") ||\n\t\tmessage.includes(\"Scope not found\") ||\n\t\tmessage.includes(\"device_not_enrolled_for_scope_group\") ||\n\t\tmessage.includes(\"device must be enrolled\")\n\t) {\n\t\treturn 404;\n\t}\n\tif (\n\t\tmessage.includes(\"not active\") ||\n\t\tmessage.includes(\"scope_not_active\") ||\n\t\tmessage.includes(\"group_archived\") ||\n\t\tmessage.includes(\"Group is archived\")\n\t) {\n\t\treturn 409;\n\t}\n\tif (\n\t\tmessage.includes(\"Remote coordinator request failed (5\") ||\n\t\tmessage.includes(\"fetch failed\") ||\n\t\tmessage.includes(\"network\") ||\n\t\tmessage.includes(\"timed out\")\n\t) {\n\t\treturn 502;\n\t}\n\treturn 400;\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\t{ defaultHttpPort: config.syncPort },\n\t\t);\n\t}\n\tif (config.syncHost && config.syncHost !== \"0.0.0.0\") {\n\t\treturn [normalizeAddress(formatHostPort(config.syncHost, config.syncPort))].filter(Boolean);\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) => normalizeAddress(formatHostPort(address, config.syncPort)))\n\t\t.filter(Boolean);\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\nconst SYNC_AUTH_STORE_BUSY_REASON = \"sync_auth_store_busy\";\n\ntype SyncAuthResult = { ok: boolean; reason: string; deviceId: string };\n\nfunction isSqliteBusy(err: unknown): boolean {\n\tif (!err || typeof err !== \"object\") return false;\n\tconst code = \"code\" in err ? String((err as { code?: unknown }).code ?? \"\") : \"\";\n\tconst message = err instanceof Error ? err.message : \"\";\n\treturn code === \"SQLITE_BUSY\" || message.includes(\"database is locked\");\n}\n\nfunction recordSyncAuthNonce(\n\tstore: MemoryStore,\n\tdeviceId: string,\n\tnonce: string,\n\tcreatedAt: string,\n): SyncAuthResult | null {\n\ttry {\n\t\tif (!recordNonce(store.db, deviceId, nonce, createdAt)) {\n\t\t\treturn { ok: false, reason: \"nonce_replay\", deviceId };\n\t\t}\n\t} catch (err) {\n\t\tif (isSqliteBusy(err)) {\n\t\t\treturn { ok: false, reason: SYNC_AUTH_STORE_BUSY_REASON, deviceId };\n\t\t}\n\t\tthrow err;\n\t}\n\n\tconst cutoff = new Date(Date.now() - DEFAULT_TIME_WINDOW_S * 2 * 1000).toISOString();\n\ttry {\n\t\tcleanupNonces(store.db, cutoff);\n\t} catch (err) {\n\t\tif (!isSqliteBusy(err)) throw err;\n\t\t// Nonce cleanup is best-effort. A lock here should not fail a request\n\t\t// after its nonce was already recorded; the next request can prune.\n\t}\n\treturn null;\n}\n\nfunction isSyncAuthStoreBusy(auth: SyncAuthResult): boolean {\n\treturn !auth.ok && auth.reason === SYNC_AUTH_STORE_BUSY_REASON;\n}\n\nfunction syncAuthStoreBusyResponse(c: Context) {\n\tc.header(\"Retry-After\", \"1\");\n\treturn c.json({ error: SYNC_AUTH_STORE_BUSY_REASON }, 503);\n}\n\nfunction authorizeSyncRequest(\n\tstore: MemoryStore,\n\trequest: { method: string; url: string; header(name: string): string | undefined },\n\tbody: Buffer,\n): SyncAuthResult {\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\tconst nonceResult = recordSyncAuthNonce(store, deviceId, nonce, createdAt);\n\tif (nonceResult) return nonceResult;\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<SyncAuthResult> {\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\tconst nonceResult = recordSyncAuthNonce(store, deviceId, nonce, createdAt);\n\tif (nonceResult) return nonceResult;\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 cleanPeerScopeText(value: unknown): string | null {\n\tconst text = String(value ?? \"\").trim();\n\treturn text || null;\n}\n\nfunction peerAuthorizedScopes(store: MemoryStore, peerDeviceId: string): Record<string, unknown>[] {\n\tconst deviceId = peerDeviceId.trim();\n\tif (!deviceId) return [];\n\tconst rows = store.db\n\t\t.prepare(\n\t\t\t`SELECT\n\t\t\t\trs.scope_id,\n\t\t\t\trs.label,\n\t\t\t\trs.kind,\n\t\t\t\trs.authority_type,\n\t\t\t\trs.coordinator_id,\n\t\t\t\trs.group_id,\n\t\t\t\tsm.role,\n\t\t\t\tsm.membership_epoch,\n\t\t\t\tsm.updated_at\n\t\t\t FROM scope_memberships sm\n\t\t\t JOIN replication_scopes rs ON rs.scope_id = sm.scope_id\n\t\t\t WHERE sm.device_id = ?\n\t\t\t AND sm.status = 'active'\n\t\t\t AND rs.status = 'active'\n\t\t\t AND sm.membership_epoch >= rs.membership_epoch\n\t\t\t ORDER BY CASE WHEN rs.authority_type = 'local' THEN 1 ELSE 0 END,\n\t\t\t rs.label COLLATE NOCASE,\n\t\t\t rs.scope_id`,\n\t\t)\n\t\t.all(deviceId) as Array<Record<string, unknown>>;\n\treturn rows.map((row) => ({\n\t\tscope_id: String(row.scope_id ?? \"\"),\n\t\tlabel: String(row.label ?? row.scope_id ?? \"\"),\n\t\tkind: String(row.kind ?? \"user\"),\n\t\tauthority_type: String(row.authority_type ?? \"local\"),\n\t\tcoordinator_id: cleanPeerScopeText(row.coordinator_id),\n\t\tgroup_id: cleanPeerScopeText(row.group_id),\n\t\trole: String(row.role ?? \"member\"),\n\t\tmembership_epoch: Number(row.membership_epoch ?? 0),\n\t\tupdated_at: cleanPeerScopeText(row.updated_at),\n\t}));\n}\n\nfunction ensureLocalActorRecord(store: MemoryStore): void {\n\tconst d = drizzle(store.db, { schema });\n\tconst now = new Date().toISOString();\n\t// Invariant: exactly one row in `actors` has is_local=1, and it is the\n\t// row whose actor_id matches store.actorId. Stale is_local=1 rows can\n\t// appear when a device's actor_id changes (config edit, regenerated\n\t// device keys, DB copied from another machine). Demote any such rows\n\t// before ensuring the canonical local row exists.\n\td.update(schema.actors)\n\t\t.set({ is_local: 0, updated_at: now })\n\t\t.where(and(eq(schema.actors.is_local, 1), ne(schema.actors.actor_id, store.actorId)))\n\t\t.run();\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) {\n\t\t// Row already exists for the canonical local actor id; the demotion\n\t\t// above guarantees it is the only is_local=1 row, but the row itself\n\t\t// may have been previously set to is_local=0 (e.g. via a stale demote\n\t\t// from an even earlier identity). Re-mark it as local idempotently.\n\t\td.update(schema.actors)\n\t\t\t.set({ is_local: 1, updated_at: now })\n\t\t\t.where(eq(schema.actors.actor_id, store.actorId))\n\t\t\t.run();\n\t\treturn;\n\t}\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 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\tconst addressCount = Array.isArray(record.addresses) ? record.addresses.length : 0;\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\taddress_count: addressCount,\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\ninterface AcceptDiscoveredPeerOptions {\n\tpeerDeviceId: string;\n\tfingerprint?: string;\n\t// Optional per-peer scope override. When undefined the group's scope\n\t// template is applied if auto_seed_scope is enabled; otherwise the peer\n\t// is enrolled with no scope filters.\n\t// Per-field: `undefined` = \"inherit from template\", `null` = \"explicit empty\",\n\t// `string[]` = \"use this list\". This avoids silently wiping the template's\n\t// exclude list when the caller only overrides include (or vice versa).\n\tscopeOverride?: {\n\t\tprojects_include?: string[] | null;\n\t\tprojects_exclude?: string[] | null;\n\t};\n\t// When provided and the caller is the admin-groups endpoint, this group\n\t// must be one of the match's coordinator groups. When undefined (legacy\n\t// /api/sync/peers/accept-discovered path) the match must belong to\n\t// exactly one group and that one is used.\n\texpectedGroupId?: string;\n}\n\ntype AcceptDiscoveredPeerNotConfiguredReason =\n\t| \"coordinator_url_missing\"\n\t| \"coordinator_groups_empty\"\n\t| \"sync_disabled\";\n\nfunction detailForNotConfiguredReason(reason: AcceptDiscoveredPeerNotConfiguredReason): string {\n\tswitch (reason) {\n\t\tcase \"coordinator_url_missing\":\n\t\t\treturn \"Configure a coordinator URL before pairing with discovered peers.\";\n\t\tcase \"coordinator_groups_empty\":\n\t\t\treturn \"Join a coordinator team before pairing with discovered peers.\";\n\t\tcase \"sync_disabled\":\n\t\t\treturn \"Enable sync on this device before pairing with discovered peers.\";\n\t}\n}\n\nasync function acceptDiscoveredPeer(\n\tstore: MemoryStore,\n\tinput: AcceptDiscoveredPeerOptions,\n): Promise<\n\t| {\n\t\t\tok: true;\n\t\t\tpeer_device_id: string;\n\t\t\tcreated: boolean;\n\t\t\tupdated: boolean;\n\t\t\tname: string | null;\n\t\t\tgroup_id: string;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\tstatus: number;\n\t\t\terror: string;\n\t\t\tdetail: string;\n\t\t\treason?: AcceptDiscoveredPeerNotConfiguredReason;\n\t }\n> {\n\tconst config = readCoordinatorSyncConfig();\n\t// Order: address the most foundational gap first so the detail string\n\t// guides the user through setup in the correct sequence.\n\tlet notConfiguredReason: AcceptDiscoveredPeerNotConfiguredReason | null = null;\n\tif (!config.syncCoordinatorUrl) {\n\t\tnotConfiguredReason = \"coordinator_url_missing\";\n\t} else if (config.syncCoordinatorGroups.length === 0) {\n\t\tnotConfiguredReason = \"coordinator_groups_empty\";\n\t} else if (!config.syncEnabled) {\n\t\tnotConfiguredReason = \"sync_disabled\";\n\t}\n\tif (notConfiguredReason) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 400,\n\t\t\terror: \"coordinator_not_configured\",\n\t\t\treason: notConfiguredReason,\n\t\t\tdetail: detailForNotConfiguredReason(notConfiguredReason),\n\t\t};\n\t}\n\tconst discovered = await lookupCoordinatorPeers(store, config);\n\tconst inputFingerprint = String(input.fingerprint ?? \"\").trim();\n\tconst candidates = discovered.filter(\n\t\t(peer) => String(peer.device_id ?? \"\").trim() === input.peerDeviceId,\n\t);\n\tconst matchingCandidates = inputFingerprint\n\t\t? candidates.filter((peer) => String(peer.fingerprint ?? \"\").trim() === inputFingerprint)\n\t\t: candidates;\n\tconst uniqueFingerprints = new Set(\n\t\tmatchingCandidates.map((peer) => String(peer.fingerprint ?? \"\").trim()).filter(Boolean),\n\t);\n\tif (!inputFingerprint && uniqueFingerprints.size > 1) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"ambiguous_discovered_peer\",\n\t\t\tdetail:\n\t\t\t\t\"That discovered device has multiple coordinator fingerprints. Enable diagnostics, refresh sync status, and choose the intended device before trusting it.\",\n\t\t};\n\t}\n\tconst match = matchingCandidates[0];\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 expiresAt = String(match.expires_at ?? \"\").trim();\n\tconst expired = expiresAt ? Date.parse(expiresAt) <= Date.now() : false;\n\tif (match.stale || expired) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"discovered_peer_stale\",\n\t\t\tdetail:\n\t\t\t\t\"This discovered device's coordinator presence is stale. Wait for it to come online and refresh sync status before trusting it.\",\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\tif (!nextFingerprint || fingerprintPublicKey(nextPublicKey) !== nextFingerprint) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"discovered_peer_fingerprint_mismatch\",\n\t\t\tdetail:\n\t\t\t\t\"This discovered device's coordinator public key does not match its fingerprint. Refresh sync status or re-enroll the device before trusting it.\",\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\tconst freshGroupIds = Array.isArray(match.fresh_groups)\n\t\t? match.fresh_groups.map((value) => String(value ?? \"\").trim()).filter(Boolean)\n\t\t: [];\n\tlet groupId: string;\n\tif (input.expectedGroupId) {\n\t\tif (!groupIds.includes(input.expectedGroupId)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 409,\n\t\t\t\terror: \"peer_not_in_group\",\n\t\t\t\tdetail:\n\t\t\t\t\t\"This discovered device is not visible through the specified coordinator group. Refresh sync status and try again.\",\n\t\t\t};\n\t\t}\n\t\tif (!freshGroupIds.includes(input.expectedGroupId)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 409,\n\t\t\t\terror: \"discovered_peer_stale\",\n\t\t\t\tdetail:\n\t\t\t\t\t\"This discovered device's coordinator presence is stale for the specified group. Wait for it to come online and refresh sync status before trusting it.\",\n\t\t\t};\n\t\t}\n\t\tgroupId = input.expectedGroupId;\n\t} else {\n\t\tif (groupIds.length !== 1) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 409,\n\t\t\t\terror: \"ambiguous_coordinator_group\",\n\t\t\t\tdetail:\n\t\t\t\t\tgroupIds.length > 1\n\t\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\t: \"This device is missing coordinator group context. Refresh sync status and try again.\",\n\t\t\t};\n\t\t}\n\t\tgroupId = groupIds[0] as string;\n\t}\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\tdiscovered_via_group_id: schema.syncPeers.discovered_via_group_id,\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(nextAddresses, existingAddresses));\n\tawait createCoordinatorReciprocalApproval(store, config, {\n\t\tgroupId,\n\t\trequestedDeviceId: input.peerDeviceId,\n\t});\n\n\t// Resolve project-scope seed. On first enrollment (no existing row), apply\n\t// the group's scope template if auto_seed_scope is enabled. Per-field\n\t// overrides fall back to the template when undefined, so passing only\n\t// `projects_include` does not silently wipe the template's exclude list.\n\t// Existing peers are not re-scoped — the template is a seed, not a live link.\n\tconst coordinatorUrl = config.syncCoordinatorUrl || null;\n\tlet scopeInclude: string | null | undefined;\n\tlet scopeExclude: string | null | undefined;\n\tif (!existing) {\n\t\tlet templateInclude: string[] | null = null;\n\t\tlet templateExclude: string[] | null = null;\n\t\tif (coordinatorUrl) {\n\t\t\tconst prefs = getCoordinatorGroupPreference(store.db, coordinatorUrl, groupId);\n\t\t\tif (prefs?.auto_seed_scope) {\n\t\t\t\ttemplateInclude = prefs.projects_include ?? null;\n\t\t\t\ttemplateExclude = prefs.projects_exclude ?? null;\n\t\t\t}\n\t\t}\n\t\tconst overrideInclude = input.scopeOverride?.projects_include;\n\t\tconst overrideExclude = input.scopeOverride?.projects_exclude;\n\t\tconst resolvedInclude = overrideInclude === undefined ? templateInclude : overrideInclude;\n\t\tconst resolvedExclude = overrideExclude === undefined ? templateExclude : overrideExclude;\n\t\tscopeInclude = resolvedInclude ? JSON.stringify(resolvedInclude) : null;\n\t\tscopeExclude = resolvedExclude ? JSON.stringify(resolvedExclude) : null;\n\t}\n\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\tprojects_include_json: scopeInclude ?? null,\n\t\t\t\t\tprojects_exclude_json: scopeExclude ?? null,\n\t\t\t\t\tcreated_at: now,\n\t\t\t\t\tlast_seen_at: now,\n\t\t\t\t\tdiscovered_via_coordinator_id: coordinatorUrl,\n\t\t\t\t\tdiscovered_via_group_id: groupId,\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\tgroup_id: groupId,\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\t// Backfill group-discovery attribution on existing rows if we know\n\t\t\t\t// it now and it wasn't stamped before. Don't overwrite a non-null\n\t\t\t\t// group reference — that would silently move the peer between\n\t\t\t\t// teams and invalidate any template-seeded scope.\n\t\t\t\t...((existing as { discovered_via_group_id?: string | null }).discovered_via_group_id\n\t\t\t\t\t? {}\n\t\t\t\t\t: { discovered_via_group_id: groupId, discovered_via_coordinator_id: coordinatorUrl }),\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\tgroup_id: groupId,\n\t\t};\n\t})();\n\treturn result;\n}\n\nfunction filterOpsForPeer(\n\tstore: MemoryStore,\n\tpeerDeviceId: string,\n\tlocalDeviceId: string | null,\n\tops: ReplicationOp[],\n\toptions: { applyScopeFilter?: boolean } = {},\n): { allowed: ReplicationOp[]; skipped: number; skippedDetail: SafeSkippedSyncDetail | null } {\n\tconst [allowed, , skipped] = filterReplicationOpsForSyncWithStatus(store.db, ops, peerDeviceId, {\n\t\tlocalDeviceId,\n\t\tapplyScopeFilter: options.applyScopeFilter,\n\t});\n\treturn {\n\t\tallowed,\n\t\tskipped: skipped?.skipped_count ?? 0,\n\t\tskippedDetail: skipped ? safeSkippedSyncDetail(skipped) : null,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Peer row mapping — deduplicated helper (fix #4)\n// ---------------------------------------------------------------------------\n\nfunction claimedLocalActorScopeStatus(\n\tstore: MemoryStore,\n\trow: Record<string, unknown>,\n): Record<string, unknown> | null {\n\tif (!row.claimed_local_actor) return null;\n\tconst peerDeviceId = String(row.peer_device_id ?? \"\").trim();\n\tconst actorId = String(row.actor_id ?? store.actorId).trim() || store.actorId;\n\tconst grant = personalScopeGrantStatusForPeer(store.db, { peerDeviceId, actorId });\n\treturn {\n\t\tscope_id: grant.scope_id,\n\t\tauthorized: grant.authorized,\n\t\tstate: grant.state,\n\t\taction_required: !grant.authorized,\n\t};\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\trecentOpsByPeer?: Map<string, { in: number; out: number }>,\n\tscopeRejectionsByPeer?: Map<string, InboundScopeRejectionPeerSummary>,\n\tlocalDeviceId?: string | null,\n): Record<string, unknown> {\n\tconst peerId = String(row.peer_device_id ?? \"\");\n\tconst recentOps = recentOpsByPeer?.get(peerId) ?? { in: 0, out: 0 };\n\tconst scopeRejections = scopeRejectionsByPeer?.get(peerId);\n\tconst addresses = safeJsonList(row.addresses_json as string | null);\n\tconst perScopeSync = listPerPeerScopeSyncState(store.db, {\n\t\tlocalDeviceId: localDeviceId ?? null,\n\t\tpeerDeviceId: peerId,\n\t});\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 ? addresses : [],\n\t\taddress_count: addresses.length,\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\tclaimed_local_actor_scope: claimedLocalActorScopeStatus(store, row),\n\t\tactor_id: row.actor_id ?? null,\n\t\tactor_display_name: row.actor_display_name ?? null,\n\t\tauthorized_scopes: peerAuthorizedScopes(store, peerId),\n\t\t// Per-Space sync state intersecting local + peer membership and joining\n\t\t// per-scope replication cursor data. Use this surface to render\n\t\t// per-Space progress in CLI/UI without exposing the legacy `status=ok`\n\t\t// shorthand that hid scoped sync gaps in 0.32.x.\n\t\tper_scope_sync: perScopeSync,\n\t\tproject_scope: {\n\t\t\t...currentProjectScope(row, readPeerProjectFilters(store, String(row.peer_device_id ?? \"\"))),\n\t\t},\n\t\trecent_ops: { in: recentOps.in, out: recentOps.out },\n\t\tscope_rejections: {\n\t\t\ttotal: scopeRejections?.total ?? 0,\n\t\t\tby_reason: scopeRejections?.by_reason ?? {},\n\t\t\tlast_at: scopeRejections?.last_at ?? null,\n\t\t},\n\t\tdiscovered_via_coordinator_id:\n\t\t\ttypeof row.discovered_via_coordinator_id === \"string\"\n\t\t\t\t? row.discovered_via_coordinator_id\n\t\t\t\t: null,\n\t\tdiscovered_via_group_id:\n\t\t\ttypeof row.discovered_via_group_id === \"string\" ? row.discovered_via_group_id : null,\n\t};\n}\n\nfunction redactSyncAttemptError(error: unknown): string | null {\n\tconst text = String(error ?? \"\").trim();\n\tif (!text) return null;\n\treturn \"sync attempt failed; enable diagnostics for details\";\n}\n\nfunction mapSyncAttemptRow(\n\trow: Record<string, unknown>,\n\tshowDiag: boolean,\n\taddresses?: string[],\n): Record<string, unknown> {\n\treturn {\n\t\t...row,\n\t\terror: showDiag ? row.error : redactSyncAttemptError(row.error),\n\t\tstatus: attemptStatus(row),\n\t\taddress: showDiag && addresses?.length ? addresses[0] : null,\n\t};\n}\n\nconst SYNC_SCOPE_REJECTION_WINDOW_SECONDS = 24 * 60 * 60;\n\nfunction recentScopeRejectionsByPeer(\n\tstore: MemoryStore,\n): Map<string, InboundScopeRejectionPeerSummary> {\n\tconst cutoff = new Date(Date.now() - SYNC_SCOPE_REJECTION_WINDOW_SECONDS * 1000).toISOString();\n\tconst summaries = summarizeInboundScopeRejections(store.db, { sinceIso: cutoff });\n\tconst map = new Map<string, InboundScopeRejectionPeerSummary>();\n\tfor (const summary of summaries) {\n\t\tconst id = String(summary.peer_device_id ?? \"\").trim();\n\t\tif (!id) continue;\n\t\tmap.set(id, summary);\n\t}\n\treturn map;\n}\n\nfunction legacySharedReviewSummary(store: MemoryStore): Record<string, unknown> {\n\tconst rows = legacySharedReviewRows(store);\n\tconst memoryCount = rows.length;\n\tconst lastUpdatedAt = rows.reduce<string | null>(\n\t\t(current, row) =>\n\t\t\trow.updated_at && (!current || row.updated_at > current) ? row.updated_at : current,\n\t\tnull,\n\t);\n\tconst ownedBySelf = store.buildOwnershipPredicate();\n\tconst candidatesByIdentity = new Map(\n\t\tlistProjectScopeCandidates(store.db, { limit: null }).map((candidate) => [\n\t\t\tcandidate.workspace_identity,\n\t\t\tcandidate,\n\t\t]),\n\t);\n\tconst groupsByIdentity = new Map<\n\t\tstring,\n\t\t{\n\t\t\tworkspace_identity: string;\n\t\t\tidentity_source: string;\n\t\t\tdisplay_project: string;\n\t\t\tmemory_count: number;\n\t\t\treassignable_memory_count: number;\n\t\t\tpeer_owned_memory_count: number;\n\t\t\tlast_updated_at: string | null;\n\t\t\tsuggested_scope_id: string | null;\n\t\t\tsuggestion_reason: string | null;\n\t\t}\n\t>();\n\tfor (const row of rows) {\n\t\tconst identity = canonicalWorkspaceIdentity({\n\t\t\tcwd: row.cwd,\n\t\t\tgitBranch: row.git_branch,\n\t\t\tgitRemote: row.git_remote,\n\t\t\tproject: row.project,\n\t\t\tworkspaceId: row.workspace_id,\n\t\t});\n\t\tconst candidate = candidatesByIdentity.get(identity.value);\n\t\tconst resolvedScope = candidate?.resolved_scope_id ?? null;\n\t\tconst suggestedScope =\n\t\t\tresolvedScope &&\n\t\t\tresolvedScope !== LOCAL_DEFAULT_SCOPE_ID &&\n\t\t\tresolvedScope !== LEGACY_SHARED_REVIEW_SCOPE_ID\n\t\t\t\t? resolvedScope\n\t\t\t\t: candidate?.suggested_scope_id;\n\t\tconst existing = groupsByIdentity.get(identity.value);\n\t\tconst isOwnedBySelf = ownedBySelf(row as unknown as Record<string, unknown>);\n\t\tconst rowUpdatedAt = row.updated_at ?? null;\n\t\tif (existing) {\n\t\t\texisting.memory_count += 1;\n\t\t\tif (isOwnedBySelf) existing.reassignable_memory_count += 1;\n\t\t\telse existing.peer_owned_memory_count += 1;\n\t\t\tif (rowUpdatedAt && (!existing.last_updated_at || rowUpdatedAt > existing.last_updated_at)) {\n\t\t\t\texisting.last_updated_at = rowUpdatedAt;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tgroupsByIdentity.set(identity.value, {\n\t\t\tworkspace_identity: identity.value,\n\t\t\tidentity_source: identity.source,\n\t\t\tdisplay_project: identity.displayProject ?? row.project ?? row.cwd ?? identity.value,\n\t\t\tmemory_count: 1,\n\t\t\treassignable_memory_count: isOwnedBySelf ? 1 : 0,\n\t\t\tpeer_owned_memory_count: isOwnedBySelf ? 0 : 1,\n\t\t\tlast_updated_at: rowUpdatedAt,\n\t\t\tsuggested_scope_id: suggestedScope ?? null,\n\t\t\tsuggestion_reason: suggestedScope\n\t\t\t\t? (candidate?.suggestion_reason ??\n\t\t\t\t\t\"Existing project mapping can be reviewed as a destination, but legacy data is not promoted automatically.\")\n\t\t\t\t: null,\n\t\t});\n\t}\n\tconst totalGroupCount = groupsByIdentity.size;\n\tconst groups = [...groupsByIdentity.values()].sort(\n\t\t(left, right) =>\n\t\t\tright.memory_count - left.memory_count ||\n\t\t\t(right.last_updated_at ?? \"\").localeCompare(left.last_updated_at ?? \"\") ||\n\t\t\tleft.workspace_identity.localeCompare(right.workspace_identity),\n\t);\n\tconst targetScopes = listSharingDomainSettingsScopes(store.db)\n\t\t.filter(\n\t\t\t(scope) =>\n\t\t\t\tscope.scope_id !== LOCAL_DEFAULT_SCOPE_ID &&\n\t\t\t\tscope.scope_id !== LEGACY_SHARED_REVIEW_SCOPE_ID,\n\t\t)\n\t\t.map((scope) => ({\n\t\t\tauthority_type: scope.authority_type,\n\t\t\tlabel: scope.label || scope.scope_id,\n\t\t\tscope_id: scope.scope_id,\n\t\t}));\n\treturn {\n\t\tscope_id: LEGACY_SHARED_REVIEW_SCOPE_ID,\n\t\tmemory_count: memoryCount,\n\t\thas_data: memoryCount > 0,\n\t\tlast_updated_at: lastUpdatedAt,\n\t\tgroups,\n\t\ttotal_group_count: totalGroupCount,\n\t\ttarget_scopes: targetScopes,\n\t};\n}\n\ninterface LegacySharedReviewReassignmentMemoryRow {\n\tid: number;\n\trev: number | null;\n\tactive: number | null;\n\tdeleted_at: string | null;\n\tupdated_at: string | null;\n\tscope_id: string | null;\n\tproject: string | null;\n\tcwd: string | null;\n\tgit_remote: string | null;\n\tgit_branch: string | null;\n\tworkspace_id: string | null;\n\tactor_id: string | null;\n\torigin_device_id: string | null;\n\tmetadata_json: string | null;\n}\n\nfunction legacySharedReviewRows(store: MemoryStore): LegacySharedReviewReassignmentMemoryRow[] {\n\treturn store.db\n\t\t.prepare(\n\t\t\t`SELECT m.id,\n\t\t\t m.rev,\n\t\t\t m.active,\n\t\t\t m.deleted_at,\n\t\t\t m.updated_at,\n\t\t\t m.scope_id,\n\t\t\t s.project,\n\t\t\t s.cwd,\n\t\t\t s.git_remote,\n\t\t\t s.git_branch,\n\t\t\t m.workspace_id,\n\t\t\t m.actor_id,\n\t\t\t m.origin_device_id,\n\t\t\t m.metadata_json\n\t\t\t FROM memory_items m\n\t\t\t LEFT JOIN sessions s ON s.id = m.session_id\n\t\t\t WHERE m.scope_id = ?\n\t\t\t AND m.active = 1\n\t\t\t AND m.deleted_at IS NULL`,\n\t\t)\n\t\t.all(LEGACY_SHARED_REVIEW_SCOPE_ID) as LegacySharedReviewReassignmentMemoryRow[];\n}\n\nfunction legacySharedReviewConfirmationToken(input: {\n\trows: LegacySharedReviewReassignmentMemoryRow[];\n\tscopeId: string;\n\tstore: MemoryStore;\n\tworkspaceIdentity: string;\n}): string {\n\tconst ownedBySelf = input.store.buildOwnershipPredicate();\n\tconst payload = input.rows\n\t\t.map((row) => {\n\t\t\tconst ownership = ownedBySelf(row as unknown as Record<string, unknown>) ? \"local\" : \"peer\";\n\t\t\treturn `${row.id}:${row.rev ?? 0}:${row.scope_id ?? \"\"}:${ownership}`;\n\t\t})\n\t\t.sort()\n\t\t.join(\",\");\n\treturn Buffer.from(`${input.workspaceIdentity}|${input.scopeId}|${payload}`, \"utf8\").toString(\n\t\t\"base64url\",\n\t);\n}\n\ninterface LegacySharedReviewReassignmentPreview {\n\tconfirmation_token: string;\n\tworkspace_identity: string;\n\tscope_id: string;\n\ttarget_scope_label: string;\n\tmemory_count: number;\n\treassignable_memory_count: number;\n\tskipped_memory_count: number;\n\taffected_peer_device_count: number;\n\taffected_peer_device_ids: string[];\n\twarning: string;\n}\n\ninterface ProjectInventoryMemoryRow {\n\tid: number;\n\trev: number | null;\n\tproject: string | null;\n\tcwd: string | null;\n\tgit_remote: string | null;\n\tgit_branch: string | null;\n\tworkspace_id: string | null;\n\tactor_id: string | null;\n\torigin_device_id: string | null;\n\tmetadata_json: string | null;\n}\n\nfunction projectInventoryRowsForWorkspace(\n\tstore: MemoryStore,\n\tworkspaceIdentity: string,\n): ProjectInventoryMemoryRow[] {\n\tconst rows = store.db\n\t\t.prepare(\n\t\t\t`SELECT m.id,\n\t\t\t m.rev,\n\t\t\t s.project,\n\t\t\t s.cwd,\n\t\t\t s.git_remote,\n\t\t\t s.git_branch,\n\t\t\t m.workspace_id,\n\t\t\t m.actor_id,\n\t\t\t m.origin_device_id,\n\t\t\t m.metadata_json\n\t\t\t FROM memory_items m\n\t\t\t LEFT JOIN sessions s ON s.id = m.session_id\n\t\t\t WHERE m.active = 1\n\t\t\t AND m.deleted_at IS NULL`,\n\t\t)\n\t\t.all() as ProjectInventoryMemoryRow[];\n\treturn rows.filter((row) => {\n\t\tconst identity = canonicalWorkspaceIdentity({\n\t\t\tcwd: row.cwd,\n\t\t\tgitBranch: row.git_branch,\n\t\t\tgitRemote: row.git_remote,\n\t\t\tproject: row.project,\n\t\t\tworkspaceId: row.workspace_id,\n\t\t});\n\t\treturn identity.value === workspaceIdentity;\n\t});\n}\n\nfunction projectForgetConfirmationToken(\n\tstore: MemoryStore,\n\trows: ProjectInventoryMemoryRow[],\n): string {\n\tconst ownedBySelf = store.buildOwnershipPredicate();\n\tconst payload = rows\n\t\t.map((row) => {\n\t\t\tconst ownership = ownedBySelf(row as unknown as Record<string, unknown>) ? \"local\" : \"peer\";\n\t\t\treturn `${row.id}:${row.rev ?? 0}:${ownership}`;\n\t\t})\n\t\t.sort()\n\t\t.join(\",\");\n\treturn Buffer.from(payload, \"utf8\").toString(\"base64url\");\n}\n\nfunction forgetProjectInventoryLocalMemories(\n\tstore: MemoryStore,\n\tinput: { confirmationToken?: string | null; confirmed: boolean; workspaceIdentity: string },\n): Record<string, unknown> {\n\tif (!input.workspaceIdentity.trim()) {\n\t\tthrow new Error(\"workspace_identity must be a non-empty string\");\n\t}\n\tconst rows = projectInventoryRowsForWorkspace(store, input.workspaceIdentity);\n\tif (rows.length === 0) throw new Error(\"project identity not found\");\n\tconst ownedBySelf = store.buildOwnershipPredicate();\n\tconst localRows = rows.filter((row) => ownedBySelf(row as unknown as Record<string, unknown>));\n\tconst confirmationToken = projectForgetConfirmationToken(store, rows);\n\tconst preview = {\n\t\tconfirmation_token: confirmationToken,\n\t\tlocal_owned_memory_count: localRows.length,\n\t\tpeer_owned_memory_count: rows.length - localRows.length,\n\t\tworkspace_identity: input.workspaceIdentity,\n\t};\n\tif (!input.confirmed) {\n\t\treturn { confirmed: false, ...preview };\n\t}\n\tif (input.confirmationToken !== confirmationToken) {\n\t\tthrow new Error(\"project memories changed before cleanup; refresh and try again\");\n\t}\n\tstore.db.transaction(() => {\n\t\tfor (const row of localRows) store.forget(row.id);\n\t})();\n\treturn { confirmed: true, forgotten_memory_count: localRows.length, ...preview };\n}\n\nfunction assertLocalDeviceScopeMembership(store: MemoryStore, scopeId: string): void {\n\tif (scopeId === LOCAL_DEFAULT_SCOPE_ID) return;\n\tconst row = store.db\n\t\t.prepare(\n\t\t\t`SELECT 1\n\t\t\t FROM scope_memberships sm\n\t\t\t JOIN replication_scopes rs ON rs.scope_id = sm.scope_id\n\t\t\t WHERE sm.scope_id = ?\n\t\t\t AND sm.device_id = ?\n\t\t\t AND sm.status = 'active'\n\t\t\t AND rs.status = 'active'\n\t\t\t AND sm.membership_epoch >= rs.membership_epoch\n\t\t\t LIMIT 1`,\n\t\t)\n\t\t.get(scopeId, store.deviceId);\n\tif (!row) throw new Error(`local device is not a member of Sharing domain ${scopeId}`);\n}\n\nfunction legacySharedReviewRowsForWorkspace(\n\tstore: MemoryStore,\n\tworkspaceIdentity: string,\n): LegacySharedReviewReassignmentMemoryRow[] {\n\treturn legacySharedReviewRows(store).filter((row) => {\n\t\tconst identity = canonicalWorkspaceIdentity({\n\t\t\tcwd: row.cwd,\n\t\t\tgitBranch: row.git_branch,\n\t\t\tgitRemote: row.git_remote,\n\t\t\tproject: row.project,\n\t\t\tworkspaceId: row.workspace_id,\n\t\t});\n\t\treturn identity.value === workspaceIdentity;\n\t});\n}\n\nfunction reassignableLegacySharedReviewRows(\n\tstore: MemoryStore,\n\trows: LegacySharedReviewReassignmentMemoryRow[],\n): LegacySharedReviewReassignmentMemoryRow[] {\n\tconst reassignableRows = rows.filter((row) =>\n\t\tstore.memoryOwnedBySelf(row as unknown as Record<string, unknown>),\n\t);\n\tif (reassignableRows.length === 0) {\n\t\tthrow new Error(\n\t\t\t\"This legacy review group contains only peer-owned memories; this device cannot reassign them to a Sharing domain.\",\n\t\t);\n\t}\n\tconst currentRows = store.db\n\t\t.prepare(\n\t\t\t`SELECT id, scope_id, active, deleted_at\n\t\t\t FROM memory_items\n\t\t\t WHERE id IN (${reassignableRows.map(() => \"?\").join(\",\")})`,\n\t\t)\n\t\t.all(...reassignableRows.map((row) => row.id)) as Array<{\n\t\tactive: number | null;\n\t\tdeleted_at: string | null;\n\t\tid: number;\n\t\tscope_id: string | null;\n\t}>;\n\tconst currentById = new Map(currentRows.map((row) => [Number(row.id), row]));\n\tfor (const row of reassignableRows) {\n\t\tconst current = currentById.get(row.id);\n\t\tif (\n\t\t\tcurrent?.scope_id !== LEGACY_SHARED_REVIEW_SCOPE_ID ||\n\t\t\tcurrent.active !== 1 ||\n\t\t\tcurrent.deleted_at\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"legacy shared review group changed before reassignment; refresh and try again\",\n\t\t\t);\n\t\t}\n\t}\n\treturn reassignableRows;\n}\n\nfunction legacySharedReviewReassignmentPreview(\n\tstore: MemoryStore,\n\tinput: { scopeId: string; workspaceIdentity: string },\n): LegacySharedReviewReassignmentPreview {\n\tif (!input.workspaceIdentity.trim())\n\t\tthrow new Error(\"workspace_identity must be a non-empty string\");\n\tif (!input.scopeId.trim()) throw new Error(\"scope_id must be a non-empty string\");\n\tif (input.scopeId === LOCAL_DEFAULT_SCOPE_ID) {\n\t\tthrow new Error(\"local-default is not a valid target for legacy shared review reassignment\");\n\t}\n\tif (input.scopeId === LEGACY_SHARED_REVIEW_SCOPE_ID) {\n\t\tthrow new Error(\"legacy-shared-review is a review bucket, not an assignable Sharing domain\");\n\t}\n\tconst targetScope = listSharingDomainSettingsScopes(store.db).find(\n\t\t(scope) => scope.scope_id === input.scopeId,\n\t);\n\tif (!targetScope) throw new Error(`scope_id ${input.scopeId} is not an active Sharing domain`);\n\tassertLocalDeviceScopeMembership(store, input.scopeId);\n\tconst rows = legacySharedReviewRowsForWorkspace(store, input.workspaceIdentity);\n\tif (rows.length === 0) throw new Error(\"legacy shared review group not found\");\n\tconst reassignableRows = reassignableLegacySharedReviewRows(store, rows);\n\tconst peerDeviceIds = [\n\t\t...new Set(\n\t\t\trows\n\t\t\t\t.map((row) => String(row.origin_device_id ?? \"\").trim())\n\t\t\t\t.filter((deviceId) => deviceId && deviceId !== store.deviceId),\n\t\t),\n\t].sort();\n\treturn {\n\t\taffected_peer_device_count: peerDeviceIds.length,\n\t\taffected_peer_device_ids: peerDeviceIds.slice(0, 5),\n\t\tconfirmation_token: legacySharedReviewConfirmationToken({\n\t\t\trows,\n\t\t\tscopeId: input.scopeId,\n\t\t\tstore,\n\t\t\tworkspaceIdentity: input.workspaceIdentity,\n\t\t}),\n\t\tmemory_count: rows.length,\n\t\treassignable_memory_count: reassignableRows.length,\n\t\tscope_id: input.scopeId,\n\t\tskipped_memory_count: rows.length - reassignableRows.length,\n\t\ttarget_scope_label: targetScope.label || targetScope.scope_id,\n\t\twarning:\n\t\t\t\"This changes future sync authorization for reassignable local memories. It does not erase data already copied to peers under legacy-shared-review.\",\n\t\tworkspace_identity: input.workspaceIdentity,\n\t};\n}\n\nfunction reassignLegacySharedReviewGroup(\n\tstore: MemoryStore,\n\tinput: { confirmationToken?: string | null; scopeId: string; workspaceIdentity: string },\n): Record<string, unknown> {\n\tconst preview = legacySharedReviewReassignmentPreview(store, input);\n\tif (input.confirmationToken !== preview.confirmation_token) {\n\t\tthrow new Error(\n\t\t\t\"legacy shared review group changed before reassignment; refresh and try again\",\n\t\t);\n\t}\n\tconst rows = reassignableLegacySharedReviewRows(\n\t\tstore,\n\t\tlegacySharedReviewRowsForWorkspace(store, input.workspaceIdentity),\n\t);\n\tstore.db.transaction(() => {\n\t\tfor (const row of rows) store.reassignMemoryScope(row.id, input.scopeId);\n\t})();\n\treturn {\n\t\tok: true,\n\t\t...preview,\n\t\treassigned_memory_count: rows.length,\n\t\tlegacy_shared_review: legacySharedReviewSummary(store),\n\t};\n}\n\n// Aggregate ops_in / ops_out across recent successful sync_attempts per peer.\n// Window: last 24 hours. Feeds the per-peer direction glyph on the Sync tab\n// (↕ bidirectional, ↑ publishing, ↓ subscribed) off real traffic instead of\n// an invented peer-role field.\nconst SYNC_DIRECTION_WINDOW_SECONDS = 24 * 60 * 60;\n\nfunction recentPeerOps(store: MemoryStore): Map<string, { in: number; out: number }> {\n\tconst cutoff = new Date(Date.now() - SYNC_DIRECTION_WINDOW_SECONDS * 1000).toISOString();\n\tconst rows = store.db\n\t\t.prepare(\n\t\t\t`SELECT peer_device_id,\n\t\t\t COALESCE(SUM(ops_in), 0) AS ops_in,\n\t\t\t COALESCE(SUM(ops_out), 0) AS ops_out\n\t\t\t FROM sync_attempts\n\t\t\t WHERE ok = 1 AND finished_at IS NOT NULL AND finished_at >= ?\n\t\t\t GROUP BY peer_device_id`,\n\t\t)\n\t\t.all(cutoff) as Array<{\n\t\tpeer_device_id: string | null;\n\t\tops_in: number | null;\n\t\tops_out: number | null;\n\t}>;\n\tconst map = new Map<string, { in: number; out: number }>();\n\tfor (const row of rows) {\n\t\tconst id = String(row.peer_device_id ?? \"\").trim();\n\t\tif (!id) continue;\n\t\tmap.set(id, { in: Number(row.ops_in ?? 0), out: Number(row.ops_out ?? 0) });\n\t}\n\treturn map;\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\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, p.discovered_via_coordinator_id, p.discovered_via_group_id,\n\t 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 * Compute the negotiated sync capability for a request by combining the\n * server's local capability with the value the caller advertised in the\n * `X-Codemem-Sync-Capability` header. Routes use this to decide whether to\n * honor scoped-sync wire features such as explicit `scope_id` parameters\n * and `/v1/status` `authorized_scopes` enumeration.\n *\n * Unsigned headers are fine here: the server is computing what it is\n * willing to do, not granting access. Per-scope authorization is enforced\n * separately via the membership cache when a scope_id is actually used.\n */\nfunction negotiatedSyncCapability(c: Context) {\n\tconst header = c.req.header(SYNC_CAPABILITY_HEADER) ?? null;\n\treturn negotiateSyncCapability(LOCAL_SYNC_CAPABILITY, normalizeSyncCapability(header));\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\tif (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\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 (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\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\tconst grantPresent = Boolean((c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim());\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sync] bootstrap grant auth failed: reason=${auth.reason} grant_present=${grantPresent} 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, true), 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\tconst negotiated = negotiatedSyncCapability(c);\n\t\t\t\tconst authorizedScopes = isScopedSyncCapability(negotiated)\n\t\t\t\t\t? listAuthorizedScopesForPeer(store.db, {\n\t\t\t\t\t\t\tlocalDeviceId: deviceId,\n\t\t\t\t\t\t\tpeerDeviceId: auth.deviceId,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null;\n\t\t\t\tconst response: Record<string, unknown> = {\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: addSyncScopeToBoundary(syncReset, null),\n\t\t\t\t\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\t\t};\n\t\t\t\tif (authorizedScopes !== null) {\n\t\t\t\t\tresponse.authorized_scopes = authorizedScopes;\n\t\t\t\t}\n\t\t\t\treturn c.json(response);\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 (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\n\t\tif (!auth.ok)\n\t\t\treturn (\n\t\t\t\trateLimitedResponse(c, c.req.path, false) ??\n\t\t\t\tc.json(unauthorizedPayload(auth.reason, true), 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 rawScopeId = c.req.query(SYNC_SCOPE_QUERY_PARAM);\n\t\t\tconst negotiated = negotiatedSyncCapability(c);\n\t\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\tconst scopeRequest = parseSyncScopeRequest(rawScopeId, rawScopeId !== undefined, {\n\t\t\t\tdb: store.db,\n\t\t\t\tlocalDeviceId,\n\t\t\t\tnegotiatedCapability: negotiated,\n\t\t\t\tpeerDeviceId,\n\t\t\t});\n\t\t\tif (!scopeRequest.ok) {\n\t\t\t\treturn c.json(\n\t\t\t\t\tsyncScopeResetRequiredPayload(\n\t\t\t\t\t\tgetSyncResetState(store.db),\n\t\t\t\t\t\tscopeRequest.reason,\n\t\t\t\t\t\tLOCAL_SYNC_CAPABILITY,\n\t\t\t\t\t\tnull,\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 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 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\tscopeId: scopeRequest.mode === \"scoped\" ? scopeRequest.scope_id : undefined,\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\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\t\t\t\t...addSyncScopeToBoundary(result.reset, scopeRequest.scope_id),\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, localDeviceId, ops);\n\t\t\treturn c.json({\n\t\t\t\treset_required: false,\n\t\t\t\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\t\tscope_id: scopeRequest.scope_id,\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\tskipped_detail: filtered.skippedDetail,\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\tif (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\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 (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\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\tconst grantPresent = Boolean((c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim());\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sync] bootstrap grant auth failed: reason=${auth.reason} grant_present=${grantPresent} 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, true), 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 rawScopeId = c.req.query(SYNC_SCOPE_QUERY_PARAM);\n\t\t\t\tconst negotiated = negotiatedSyncCapability(c);\n\t\t\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\t\tconst scopeRequest = parseSyncScopeRequest(rawScopeId, rawScopeId !== undefined, {\n\t\t\t\t\tdb: store.db,\n\t\t\t\t\tlocalDeviceId,\n\t\t\t\t\tnegotiatedCapability: negotiated,\n\t\t\t\t\tpeerDeviceId: auth.deviceId,\n\t\t\t\t});\n\t\t\t\tif (!scopeRequest.ok) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\tsyncScopeResetRequiredPayload(\n\t\t\t\t\t\t\tgetSyncResetState(store.db),\n\t\t\t\t\t\t\tscopeRequest.reason,\n\t\t\t\t\t\t\tLOCAL_SYNC_CAPABILITY,\n\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t409,\n\t\t\t\t\t);\n\t\t\t\t}\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\tscopeId: scopeRequest.mode === \"scoped\" ? scopeRequest.scope_id : undefined,\n\t\t\t\t});\n\n\t\t\t\treturn c.json({\n\t\t\t\t\tscope_id: scopeRequest.scope_id,\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\tsync_capability: LOCAL_SYNC_CAPABILITY,\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 (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\n\t\tif (!auth.ok)\n\t\t\treturn (\n\t\t\t\trateLimitedResponse(c, c.req.path, false) ??\n\t\t\t\tc.json(unauthorizedPayload(auth.reason, true), 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\tconst negotiated = negotiateSyncCapability(\n\t\t\tLOCAL_SYNC_CAPABILITY,\n\t\t\tnormalizeSyncCapability(body.sync_capability),\n\t\t);\n\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\tconst scopeRequest = parseSyncScopeRequest(body.scope_id, Object.hasOwn(body, \"scope_id\"), {\n\t\t\tdb: store.db,\n\t\t\tlocalDeviceId,\n\t\t\tnegotiatedCapability: negotiated,\n\t\t\tpeerDeviceId,\n\t\t});\n\t\tif (!scopeRequest.ok) {\n\t\t\treturn c.json(\n\t\t\t\tsyncScopeResetRequiredPayload(\n\t\t\t\t\tgetSyncResetState(store.db),\n\t\t\t\t\tscopeRequest.reason,\n\t\t\t\t\tLOCAL_SYNC_CAPABILITY,\n\t\t\t\t\tnull,\n\t\t\t\t),\n\t\t\t\t409,\n\t\t\t);\n\t\t}\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\t// Inbound POSTs still use legacy visibility/project filters, but must not run\n\t\t// the outbound scope gate. Unsupported peers deliberately bypass strict inbound\n\t\t// scope rejection during rollout, so outbound filtering would silently drop data.\n\t\tconst filtered = filterOpsForPeer(store, peerDeviceId, localDeviceId, normalizedOps, {\n\t\t\tapplyScopeFilter: false,\n\t\t});\n\t\t// Scope validation runs against the full signed batch so bad scoped ops cannot\n\t\t// evade fail-closed rejection by also tripping peer project filters.\n\t\tconst rejected = rejectInboundScopeFailures(store.db, normalizedOps, localDeviceId, {\n\t\t\tenabled: negotiated !== \"unsupported\",\n\t\t\tpeerDeviceId,\n\t\t});\n\t\tif (rejected) {\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: \"scope_rejected\",\n\t\t\t\t\treason: rejected.rejections[0]?.reason ?? \"scope_mismatch\",\n\t\t\t\t\trejections: rejected.rejections,\n\t\t\t\t\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\t\t\tscope_id: scopeRequest.scope_id,\n\t\t\t\t},\n\t\t\t\t403,\n\t\t\t);\n\t\t}\n\n\t\tconst result = applyReplicationOps(store.db, filtered.allowed, localDeviceId, store.scanner);\n\t\tconst skipped = result.skipped + filtered.skipped;\n\t\treturn c.json({\n\t\t\t...result,\n\t\t\tskipped,\n\t\t\tskipped_detail: filtered.skippedDetail,\n\t\t\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\tscope_id: scopeRequest.scope_id,\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\t// Always take the fast COUNT(DISTINCT) path. The slow\n\t\t\t// per-memory vec0 probe blocks the event loop for seconds on\n\t\t\t// larger DBs, which hangs every concurrent request — not\n\t\t\t// acceptable from a status endpoint. See codemem-00jn.\n\t\t\tconst semanticIndex = traceSync(\"semanticIndex\", () =>\n\t\t\t\tredactSemanticIndexDiagnostics(getSemanticIndexDiagnostics(store.db), showDiag),\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\t// The sync daemon runs inside the viewer-server process itself, so\n\t\t\t// if this request is being served, the daemon is by definition\n\t\t\t// running — the viewer is serving us right now. The prior\n\t\t\t// `portOpen` self-probe occasionally timed out under GC / socket\n\t\t\t// backlog pressure and mis-reported \"stopped · unreachable\" while\n\t\t\t// every other request kept succeeding. Trust the pidfile's\n\t\t\t// existence (a record was written at startup) and skip the loopback\n\t\t\t// probe.\n\t\t\tconst daemonRunning = Boolean(viewerBinding);\n\t\t\tconst daemonDetail = viewerBinding\n\t\t\t\t? `viewer pidfile at ${viewerBinding.host}:${viewerBinding.port}`\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\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\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 recentOpsByPeer = traceSync(\"recentPeerOps\", () => recentPeerOps(store));\n\t\t\tconst scopeRejectionsByPeer = traceSync(\"recentScopeRejectionsByPeer\", () =>\n\t\t\t\trecentScopeRejectionsByPeer(store),\n\t\t\t);\n\t\t\tconst peersItems = peerRows.map((row) => {\n\t\t\t\tconst peer = mapPeerRow(\n\t\t\t\t\tstore,\n\t\t\t\t\trow,\n\t\t\t\t\tshowDiag,\n\t\t\t\t\trecentOpsByPeer,\n\t\t\t\t\tscopeRejectionsByPeer,\n\t\t\t\t\t(deviceRow?.device_id as string | null | undefined) ?? null,\n\t\t\t\t);\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\tlocal_sync_capability: schema.syncAttempts.local_sync_capability,\n\t\t\t\t\t\tpeer_sync_capability: schema.syncAttempts.peer_sync_capability,\n\t\t\t\t\t\tnegotiated_sync_capability: schema.syncAttempts.negotiated_sync_capability,\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 mapSyncAttemptRow(row, showDiag, addrs);\n\t\t\t});\n\t\t\tconst latestAttemptError = String(attemptRows[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 legacyReview = traceSync(\"legacySharedReview\", () => legacySharedReviewSummary(store));\n\t\t\tconst sharingReview = traceSync(\"sharingReview\", () => store.sharingReviewSummary(project));\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\tlegacy_shared_review: legacyReview,\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\tconst recentOpsByPeer = recentPeerOps(store);\n\t\t\tconst scopeRejectionsByPeer = recentScopeRejectionsByPeer(store);\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst deviceRow = d\n\t\t\t\t.select({ device_id: schema.syncDevice.device_id })\n\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t.limit(1)\n\t\t\t\t.get();\n\t\t\tconst localDeviceId = (deviceRow?.device_id as string | null | undefined) ?? null;\n\t\t\t// Use deduplicated mapPeerRow helper (fix #4)\n\t\t\tconst peers = rows.map((row) =>\n\t\t\t\tmapPeerRow(store, row, showDiag, recentOpsByPeer, scopeRejectionsByPeer, localDeviceId),\n\t\t\t);\n\t\t\treturn c.json({ items: peers, redacted: !showDiag });\n\t\t}\n\t});\n\n\t// GET /api/sync/peers/:peer_device_id/scope-rejections\n\t//\n\t// Recent scope-rejection records produced by the inbound fail-closed gate.\n\t// Each row is metadata only — op id, entity ref, scope id, reason code,\n\t// timestamp. The rejection log never stores op payloads, so this endpoint\n\t// can never leak inbound payload contents regardless of diagnostics state.\n\tapp.get(\"/api/sync/peers/:peer_device_id/scope-rejections\", (c) => {\n\t\tconst store = getStore();\n\t\tconst peerDeviceId = String(c.req.param(\"peer_device_id\") || \"\").trim();\n\t\tif (!peerDeviceId) return c.json({ error: \"missing_peer_device_id\" }, 400);\n\t\tconst limit = queryInt(c.req.query(\"limit\"), 100);\n\t\tif (limit <= 0) return c.json({ error: \"invalid_limit\" }, 400);\n\t\tconst sinceMinutesRaw = queryInt(c.req.query(\"sinceMinutes\"), 24 * 60);\n\t\t// Cap at ~10 years so a hostile or fat-fingered query cannot push the\n\t\t// computed timestamp past the Date range and turn toISOString() into\n\t\t// a 500. Anything older than 10 years is effectively \"all rejections\".\n\t\tconst SINCE_MINUTES_MAX = 10 * 365 * 24 * 60;\n\t\tconst sinceMinutes = Math.min(Math.max(sinceMinutesRaw, 0), SINCE_MINUTES_MAX);\n\t\tconst sinceIso =\n\t\t\tsinceMinutes > 0 ? new Date(Date.now() - sinceMinutes * 60_000).toISOString() : undefined;\n\t\tconst records = listInboundScopeRejections(store.db, {\n\t\t\tpeerDeviceId,\n\t\t\tsinceIso,\n\t\t\tlimit,\n\t\t});\n\t\tconst summaries = summarizeInboundScopeRejections(store.db, {\n\t\t\tpeerDeviceId,\n\t\t\tsinceIso,\n\t\t});\n\t\tconst summary = summaries[0] ?? {\n\t\t\tpeer_device_id: peerDeviceId,\n\t\t\ttotal: 0,\n\t\t\tby_reason: {},\n\t\t\tlast_at: null,\n\t\t};\n\t\treturn c.json({\n\t\t\tpeer_device_id: peerDeviceId,\n\t\t\tsummary,\n\t\t\titems: records,\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\tlocal_sync_capability: schema.syncAttempts.local_sync_capability,\n\t\t\t\t\tpeer_sync_capability: schema.syncAttempts.peer_sync_capability,\n\t\t\t\t\tnegotiated_sync_capability: schema.syncAttempts.negotiated_sync_capability,\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\tconst showDiag = queryBool(c.req.query(\"includeDiagnostics\"));\n\t\t\tconst items = rows.map((row) => mapSyncAttemptRow(row, showDiag));\n\t\t\treturn c.json({ items, redacted: !showDiag });\n\t\t}\n\t});\n\n\t// GET /api/sync/pairing — uses ensureDeviceIdentity from core (fix #5 context)\n\t//\n\t// The pairing payload is not redacted by the generic diagnostics toggle:\n\t// it is the actual command the user shares with their own other devices,\n\t// and the UI already hides it inside a \"Show pairing command\" disclosure\n\t// that they explicitly open. Redacting the payload here broke the\n\t// happy-path pairing flow because the UI had nothing to render as the\n\t// command when diagnostics were off.\n\tapp.get(\"/api/sync/pairing\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst config = readCoordinatorSyncConfig();\n\t\t\tconst d = drizzle(store.db, { schema });\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\ttry {\n\t\t\t\tconst [id, fp] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\t\tdeviceId = id;\n\t\t\t\tfingerprint = fp;\n\t\t\t\tconst row = d\n\t\t\t\t\t.select({ public_key: schema.syncDevice.public_key })\n\t\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t\t.where(eq(schema.syncDevice.device_id, id))\n\t\t\t\t\t.get();\n\t\t\t\tpublicKey = row?.public_key ?? \"\";\n\t\t\t} catch {\n\t\t\t\treturn c.json({ error: \"device identity unavailable\" }, 500);\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, { scanner: store.scanner });\n\t\t\titems.push({\n\t\t\t\tpeer_device_id: peerId,\n\t\t\t\t...result,\n\t\t\t\tskippedOut: undefined,\n\t\t\t\tskipped_out: safeSkippedSyncDetail(result.skippedOut),\n\t\t\t});\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.get(\"/api/sync/sharing-domains/settings\", (c) => {\n\t\tconst store = getStore();\n\t\tconst limit = Math.max(1, queryInt(c.req.query(\"limit\"), 250));\n\t\treturn c.json({\n\t\t\tscopes: listSharingDomainSettingsScopes(store.db),\n\t\t\tmappings: listProjectScopeSettingsMappings(store.db),\n\t\t\tprojects: listProjectScopeCandidates(store.db, { limit }),\n\t\t\tlocal_default_scope_id: LOCAL_DEFAULT_SCOPE_ID,\n\t\t});\n\t});\n\n\tapp.get(\"/api/sync/projects\", (c) => {\n\t\tconst store = getStore();\n\t\tconst limit = Math.max(1, queryInt(c.req.query(\"limit\"), 50));\n\t\tconst offset = Math.max(0, queryInt(c.req.query(\"offset\"), 0));\n\t\treturn c.json(\n\t\t\tlistProjectScopeInventory(store.db, {\n\t\t\t\tidentitySource: c.req.query(\"identity_source\"),\n\t\t\t\tlimit,\n\t\t\t\toffset,\n\t\t\t\tquery: c.req.query(\"q\"),\n\t\t\t\tscopeId: c.req.query(\"scope_id\"),\n\t\t\t\tstatus: c.req.query(\"status\"),\n\t\t\t}),\n\t\t);\n\t});\n\n\tapp.post(\"/api/sync/projects/reassign-project\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst workspaceIdentity = optionalViewerStrictString(body, \"workspace_identity\") ?? \"\";\n\t\t\tconst project = optionalViewerStrictString(body, \"project\") ?? \"\";\n\t\t\tconst result = reassignProjectScopeInventoryProject(store.db, {\n\t\t\t\tproject,\n\t\t\t\tworkspaceIdentity,\n\t\t\t});\n\t\t\treturn c.json({ ok: true, ...result });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message }, message.includes(\"not found\") ? 404 : 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/projects/forget\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst workspaceIdentity = optionalViewerStrictString(body, \"workspace_identity\") ?? \"\";\n\t\t\tconst confirmationToken = optionalViewerStrictString(body, \"confirmation_token\");\n\t\t\tconst confirmed = body.confirmed === true;\n\t\t\tconst result = forgetProjectInventoryLocalMemories(store, {\n\t\t\t\tconfirmationToken,\n\t\t\t\tconfirmed,\n\t\t\t\tworkspaceIdentity,\n\t\t\t});\n\t\t\tif (!confirmed) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"project_forget_confirmation_required\",\n\t\t\t\t\t\tpreview: result,\n\t\t\t\t\t},\n\t\t\t\t\t409,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json({ ok: true, ...result });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message }, message.includes(\"not found\") ? 404 : 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/legacy-shared-review/reassign\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst workspaceIdentity = optionalViewerStrictString(body, \"workspace_identity\") ?? \"\";\n\t\t\tconst scopeId = optionalViewerStrictString(body, \"scope_id\") ?? \"\";\n\t\t\tconst confirmationToken = optionalViewerStrictString(body, \"confirmation_token\");\n\t\t\tconst confirmedOldCopies = body.confirmed_old_copies === true;\n\t\t\tconst preview = legacySharedReviewReassignmentPreview(store, {\n\t\t\t\tscopeId,\n\t\t\t\tworkspaceIdentity,\n\t\t\t});\n\t\t\tif (!confirmedOldCopies) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"legacy_review_confirmation_required\",\n\t\t\t\t\t\tmessage: preview.warning,\n\t\t\t\t\t\tpreview,\n\t\t\t\t\t},\n\t\t\t\t\t409,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json(\n\t\t\t\treassignLegacySharedReviewGroup(store, {\n\t\t\t\t\tconfirmationToken,\n\t\t\t\t\tscopeId,\n\t\t\t\t\tworkspaceIdentity,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message }, message.includes(\"not found\") ? 404 : 400);\n\t\t}\n\t});\n\n\tapp.put(\"/api/sync/sharing-domains/project-mappings\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst confirmedGuardrailTokens = optionalViewerStringList(body, \"confirmed_guardrail_tokens\");\n\t\t\tconst mappingInput = parseViewerProjectMappingInput(body);\n\t\t\tconst analysis = analyzeProjectScopeMappingChangeGuardrails(store.db, mappingInput);\n\t\t\tif (analysis.requested_workspace_identity?.startsWith(\"unmapped:\")) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"unmapped_project_local_only\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Unmapped projects need a stable path, git remote, or workspace id before assigning a Sharing domain.\",\n\t\t\t\t\t\tguardrail_warnings: analysis.warnings,\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst missingConfirmations = missingGuardrailConfirmations(\n\t\t\t\tanalysis.warnings,\n\t\t\t\tconfirmedGuardrailTokens,\n\t\t\t);\n\t\t\tif (missingConfirmations.length > 0) {\n\t\t\t\tconst missingCodes = [...new Set(missingConfirmations.map((warning) => warning.code))];\n\t\t\t\tconst missingTokens = [\n\t\t\t\t\t...new Set(missingConfirmations.map((warning) => warning.confirmation_token)),\n\t\t\t\t].filter((token): token is string => typeof token === \"string\" && token.length > 0);\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"guardrail_confirmation_required\",\n\t\t\t\t\t\trequired_guardrails: missingCodes,\n\t\t\t\t\t\trequired_guardrail_tokens: missingTokens,\n\t\t\t\t\t\tguardrail_warnings: analysis.warnings,\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 mapping = upsertProjectScopeSettingsMapping(store.db, {\n\t\t\t\t...mappingInput,\n\t\t\t});\n\t\t\treturn c.json({ ok: true, mapping, guardrail_warnings: analysis.warnings });\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.put(\"/api/sync/sharing-domains/project-mappings/bulk\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst rawMappings = body.mappings;\n\t\t\tif (!Array.isArray(rawMappings) || rawMappings.length === 0) {\n\t\t\t\treturn c.json({ error: \"mappings must be a non-empty array\" }, 400);\n\t\t\t}\n\t\t\tconst mappingInputs = rawMappings.map((raw) => {\n\t\t\t\tif (raw == null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\t\t\t\tthrow new Error(\"each mapping must be an object\");\n\t\t\t\t}\n\t\t\t\treturn parseViewerProjectMappingInput(raw as Record<string, unknown>);\n\t\t\t});\n\t\t\tconst analyses = mappingInputs.map((mappingInput) =>\n\t\t\t\tanalyzeProjectScopeMappingChangeGuardrails(store.db, mappingInput),\n\t\t\t);\n\t\t\tconst unmapped = analyses.find((analysis) =>\n\t\t\t\tanalysis.requested_workspace_identity?.startsWith(\"unmapped:\"),\n\t\t\t);\n\t\t\tif (unmapped) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"unmapped_project_local_only\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Unmapped projects need a stable path, git remote, or workspace id before assigning a Sharing domain.\",\n\t\t\t\t\t\tguardrail_warnings: unmapped.warnings,\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst missingConfirmations = analyses.flatMap((analysis) =>\n\t\t\t\tmissingGuardrailConfirmations(analysis.warnings, []),\n\t\t\t);\n\t\t\tif (missingConfirmations.length > 0) {\n\t\t\t\tconst missingCodes = [...new Set(missingConfirmations.map((warning) => warning.code))];\n\t\t\t\tconst missingTokens = [\n\t\t\t\t\t...new Set(missingConfirmations.map((warning) => warning.confirmation_token)),\n\t\t\t\t].filter((token): token is string => typeof token === \"string\" && token.length > 0);\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"guardrail_confirmation_required\",\n\t\t\t\t\t\trequired_guardrails: missingCodes,\n\t\t\t\t\t\trequired_guardrail_tokens: missingTokens,\n\t\t\t\t\t\tguardrail_warnings: analyses.flatMap((analysis) => analysis.warnings),\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 saveMappings = store.db.transaction(() =>\n\t\t\t\tmappingInputs.map((mappingInput) =>\n\t\t\t\t\tupsertProjectScopeSettingsMapping(store.db, mappingInput),\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\tmappings: saveMappings(),\n\t\t\t\tguardrail_warnings: analyses.flatMap((analysis) => analysis.warnings),\n\t\t\t});\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.delete(\"/api/sync/sharing-domains/project-mappings/:id\", (c) => {\n\t\tconst store = getStore();\n\t\tconst id = Number(c.req.param(\"id\"));\n\t\ttry {\n\t\t\tconst deleted = deleteProjectScopeSettingsMapping(store.db, id);\n\t\t\treturn c.json({ ok: true, deleted });\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/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\ttry {\n\t\t\tconst result = await acceptDiscoveredPeer(store, {\n\t\t\t\tpeerDeviceId,\n\t\t\t\tfingerprint: fingerprint || undefined,\n\t\t\t});\n\t\t\tif (!result.ok) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: result.error,\n\t\t\t\t\t\tdetail: result.detail,\n\t\t\t\t\t\t...(result.reason ? { reason: result.reason } : {}),\n\t\t\t\t\t},\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\t// POST /api/sync/invites/import accepts both team invites (coordinator\n\t// invite envelope or codemem:// link) and device-pairing payloads\n\t// (base64 JSON with { device_id, fingerprint, public_key, addresses }).\n\t// The server discriminates by decoding the pasted text — UI callers get\n\t// one textarea for both flows. Response carries `type: \"team_join\"` or\n\t// `type: \"pair\"` so the UI can render the right success message.\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 rawValue = String(body.invite ?? \"\").trim();\n\t\tif (!rawValue) return c.json({ error: \"invite required\" }, 400);\n\n\t\t// Users often paste the whole shell command emitted by the Pairing\n\t\t// diagnostics disclosure (`echo '<b64>' | base64 -d | codemem sync\n\t\t// pair --accept-file -`). Peel the base64 out if we see that shape.\n\t\tconst shellMatch = rawValue.match(\n\t\t\t/echo\\s+['\"]([A-Za-z0-9+/=]+)['\"]\\s*\\|\\s*base64\\s+-d\\s*\\|\\s*codemem/,\n\t\t);\n\t\tconst normalized = shellMatch?.[1]?.trim() || rawValue;\n\n\t\tconst pairingResult = tryParsePairingPayload(normalized);\n\t\tif (pairingResult?.kind === \"invalid-pair\") {\n\t\t\treturn c.json({ error: pairingResult.error }, 400);\n\t\t}\n\t\tif (pairingResult?.kind === \"pair\") {\n\t\t\ttry {\n\t\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\t\tconst existing = d\n\t\t\t\t\t.select({ pinned_fingerprint: schema.syncPeers.pinned_fingerprint })\n\t\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, pairingResult.device_id))\n\t\t\t\t\t.get();\n\t\t\t\tconst existingFingerprint = String(existing?.pinned_fingerprint ?? \"\").trim();\n\t\t\t\tif (existingFingerprint && existingFingerprint !== pairingResult.fingerprint) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror: \"peer_conflict\",\n\t\t\t\t\t\t\tdetail:\n\t\t\t\t\t\t\t\t\"Pairing payload conflicts with the existing trusted fingerprint for this device. Remove or repair the old peer before accepting this pairing payload.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t409,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tupdatePeerAddresses(store.db, pairingResult.device_id, pairingResult.addresses, {\n\t\t\t\t\tpinnedFingerprint: pairingResult.fingerprint,\n\t\t\t\t\tpublicKey: pairingResult.public_key,\n\t\t\t\t\treplaceTrust: true,\n\t\t\t\t});\n\t\t\t\treturn c.json({\n\t\t\t\t\tok: true,\n\t\t\t\t\ttype: \"pair\",\n\t\t\t\t\tpeer_device_id: pairingResult.device_id,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error) }, 400);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = await coordinatorImportInviteAction({\n\t\t\t\tinviteValue: rawValue,\n\t\t\t\tdbPath: store.dbPath,\n\t\t\t});\n\t\t\treturn c.json({ ...result, type: \"team_join\" });\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 }, coordinatorAdminMutationStatus(message));\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\ttry {\n\t\t\t\tconst defaultSpace = await ensureDefaultSpaceForTeam({\n\t\t\t\t\tstore: getStore(),\n\t\t\t\t\tconfig,\n\t\t\t\t\tgroupId,\n\t\t\t\t\tdisplayName: displayName || group.display_name || null,\n\t\t\t\t});\n\t\t\t\treturn c.json({ ok: true, group, default_space: defaultSpace, status });\n\t\t\t} catch (setupError) {\n\t\t\t\treturn c.json({\n\t\t\t\t\tok: true,\n\t\t\t\t\tgroup,\n\t\t\t\t\tdefault_space: null,\n\t\t\t\t\tsetup_warning: {\n\t\t\t\t\t\tstep: \"default_space\",\n\t\t\t\t\t\terror: setupError instanceof Error ? setupError.message : String(setupError),\n\t\t\t\t\t},\n\t\t\t\t\tstatus,\n\t\t\t\t});\n\t\t\t}\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\tconst groups = removeConfiguredCoordinatorGroup(groupId);\n\t\t\treturn c.json({\n\t\t\t\tok: true,\n\t\t\t\tgroup,\n\t\t\t\tstatus: coordinatorAdminStatusPayload(),\n\t\t\t\tdisconnected_group_id: groupId,\n\t\t\t\tgroups,\n\t\t\t});\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.get(\"/api/coordinator/admin/groups/:group_id/scopes\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\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 items = await coordinatorListScopesAction({\n\t\t\t\tgroupId,\n\t\t\t\tincludeInactive: queryBool(c.req.query(\"include_inactive\")),\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, 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 }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/scopes\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\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\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\", status }, 400);\n\t\tconst scopeId = optionalViewerString(body, \"scope_id\");\n\t\tconst label = optionalViewerString(body, \"label\");\n\t\tconst membershipEpoch = optionalViewerNumber(body, \"membership_epoch\");\n\t\tif (!scopeId || !label) return c.json({ error: \"scope_id and label required\", status }, 400);\n\t\tif (Number.isNaN(membershipEpoch)) {\n\t\t\treturn c.json({ error: \"membership_epoch must be number\", status }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst scope = await coordinatorCreateScopeAction({\n\t\t\t\tgroupId,\n\t\t\t\tscopeId,\n\t\t\t\tlabel,\n\t\t\t\tkind: optionalViewerString(body, \"kind\"),\n\t\t\t\tauthorityType: optionalViewerString(body, \"authority_type\"),\n\t\t\t\tcoordinatorId: optionalViewerString(body, \"coordinator_id\"),\n\t\t\t\tmanifestIssuerDeviceId: optionalViewerString(body, \"manifest_issuer_device_id\"),\n\t\t\t\tmembershipEpoch,\n\t\t\t\tmanifestHash: optionalViewerString(body, \"manifest_hash\"),\n\t\t\t\tstatus: optionalViewerString(body, \"status\"),\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, scope, group_id: groupId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message, status }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.patch(\"/api/coordinator/admin/groups/:group_id/scopes/:scope_id\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tconst scopeId = String(c.req.param(\"scope_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (!scopeId) return c.json({ error: \"scope_id required\", status }, 400);\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\", status }, 400);\n\t\tconst membershipEpoch = optionalViewerNumber(body, \"membership_epoch\");\n\t\tif (Number.isNaN(membershipEpoch)) {\n\t\t\treturn c.json({ error: \"membership_epoch must be number\", status }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst scope = await coordinatorUpdateScopeAction({\n\t\t\t\tgroupId,\n\t\t\t\tscopeId,\n\t\t\t\tlabel: body.label === undefined ? undefined : optionalViewerString(body, \"label\"),\n\t\t\t\tkind: body.kind === undefined ? undefined : optionalViewerString(body, \"kind\"),\n\t\t\t\tauthorityType:\n\t\t\t\t\tbody.authority_type === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: optionalViewerString(body, \"authority_type\"),\n\t\t\t\tcoordinatorId:\n\t\t\t\t\tbody.coordinator_id === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: optionalViewerString(body, \"coordinator_id\"),\n\t\t\t\tmanifestIssuerDeviceId:\n\t\t\t\t\tbody.manifest_issuer_device_id === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: optionalViewerString(body, \"manifest_issuer_device_id\"),\n\t\t\t\tmembershipEpoch,\n\t\t\t\tmanifestHash:\n\t\t\t\t\tbody.manifest_hash === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: optionalViewerString(body, \"manifest_hash\"),\n\t\t\t\tstatus: body.status === undefined ? undefined : optionalViewerString(body, \"status\"),\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!scope) return c.json({ error: \"scope_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, scope, group_id: groupId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message, status }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.get(\"/api/coordinator/admin/groups/:group_id/scopes/:scope_id/members\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tconst scopeId = String(c.req.param(\"scope_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (!scopeId) return c.json({ error: \"scope_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst items = await coordinatorListScopeMembershipsAction({\n\t\t\t\tgroupId,\n\t\t\t\tscopeId,\n\t\t\t\tincludeRevoked: queryBool(c.req.query(\"include_revoked\")),\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, group_id: groupId, scope_id: scopeId, 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 }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/scopes/:scope_id/members\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tconst scopeId = String(c.req.param(\"scope_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (!scopeId) return c.json({ error: \"scope_id required\", status }, 400);\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\", status }, 400);\n\t\tconst deviceId = optionalViewerString(body, \"device_id\");\n\t\tconst membershipEpoch = optionalViewerNumber(body, \"membership_epoch\");\n\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\tif (Number.isNaN(membershipEpoch)) {\n\t\t\treturn c.json({ error: \"membership_epoch must be number\", status }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst membership = await coordinatorGrantScopeMembershipAction({\n\t\t\t\tgroupId,\n\t\t\t\tscopeId,\n\t\t\t\tdeviceId,\n\t\t\t\trole: optionalViewerString(body, \"role\"),\n\t\t\t\tmembershipEpoch,\n\t\t\t\tcoordinatorId: optionalViewerString(body, \"coordinator_id\"),\n\t\t\t\tmanifestIssuerDeviceId: optionalViewerString(body, \"manifest_issuer_device_id\"),\n\t\t\t\tmanifestHash: optionalViewerString(body, \"manifest_hash\"),\n\t\t\t\tsignedManifestJson: optionalViewerString(body, \"signed_manifest_json\"),\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, membership, group_id: groupId, scope_id: scopeId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message, status }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.post(\n\t\t\"/api/coordinator/admin/groups/:group_id/scopes/:scope_id/members/:device_id/revoke\",\n\t\tasync (c) => {\n\t\t\tconst config = readCoordinatorSyncConfig();\n\t\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\n\t\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\t\tconst scopeId = String(c.req.param(\"scope_id\") ?? \"\").trim();\n\t\t\tconst deviceId = String(c.req.param(\"device_id\") ?? \"\").trim();\n\t\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\t\tif (!scopeId) return c.json({ error: \"scope_id required\", status }, 400);\n\t\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\t\tconst body = await parseViewerJsonBody(c, { allowEmpty: true });\n\t\t\tif (!body) return c.json({ error: \"invalid json\", status }, 400);\n\t\t\tconst membershipEpoch = optionalViewerNumber(body, \"membership_epoch\");\n\t\t\tif (Number.isNaN(membershipEpoch)) {\n\t\t\t\treturn c.json({ error: \"membership_epoch must be number\", status }, 400);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst ok = await coordinatorRevokeScopeMembershipAction({\n\t\t\t\t\tgroupId,\n\t\t\t\t\tscopeId,\n\t\t\t\t\tdeviceId,\n\t\t\t\t\tmembershipEpoch,\n\t\t\t\t\tmanifestHash: optionalViewerString(body, \"manifest_hash\"),\n\t\t\t\t\tsignedManifestJson: optionalViewerString(body, \"signed_manifest_json\"),\n\t\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t\t});\n\t\t\t\tif (!ok) return c.json({ error: \"membership_not_found\", status }, 404);\n\t\t\t\treturn c.json({\n\t\t\t\t\tok: true,\n\t\t\t\t\tgroup_id: groupId,\n\t\t\t\t\tscope_id: scopeId,\n\t\t\t\t\tdevice_id: deviceId,\n\t\t\t\t\tstatus,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\treturn c.json({ error: message, status }, coordinatorAdminMutationStatus(message));\n\t\t\t}\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 }, coordinatorAdminMutationStatus(message));\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\tlet defaultSpaceMembership = null;\n\t\t\tlet setupWarning = null;\n\t\t\ttry {\n\t\t\t\tdefaultSpaceMembership = await maybeGrantDefaultSpaceOnJoin({\n\t\t\t\t\tstore: getStore(),\n\t\t\t\t\tconfig,\n\t\t\t\t\tgroupId: result.group_id,\n\t\t\t\t\tdeviceId: result.device_id,\n\t\t\t\t});\n\t\t\t} catch (grantError) {\n\t\t\t\tsetupWarning = {\n\t\t\t\t\tstep: \"default_space_grant\",\n\t\t\t\t\terror: grantError instanceof Error ? grantError.message : String(grantError),\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\trequest: result,\n\t\t\t\tdefault_space_membership: defaultSpaceMembership,\n\t\t\t\tsetup_warning: setupWarning,\n\t\t\t\tstatus,\n\t\t\t});\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 }, coordinatorAdminMutationStatus(message));\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/enable\", 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 coordinatorEnableDeviceAction({\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\t// Unified peer-enrollment entry point. Mode is chosen by an explicit\n\t// body field so a legitimate coordinator group named (for example)\n\t// `none` cannot collide with the manual-pairing path:\n\t// - `mode: \"discovered\"` (default) → promote a coordinator-discovered\n\t// device, seed scope from the :group_id group's template when\n\t// auto_seed_scope is true and the caller didn't pass an override.\n\t// - `mode: \"manual\"` → manual pairing. Accepts peer_public_key +\n\t// optional name/fingerprint/addresses; :group_id path param is\n\t// ignored and both discovery columns are left null.\n\t// See docs/plans/2026-04-22-multi-team-coordinator-groups-design.md.\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/enroll-peer\", 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\t// Admin-secret gating happens inside the discovered branch below —\n\t\t// manual pairing only writes a local sync_peers row and doesn't need\n\t\t// coordinator-admin privileges, matching the pre-existing /peers/accept\n\t\t// path.\n\t\tconst rawGroupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!rawGroupId) return c.json({ error: \"group_id required\" }, 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\" }, 400);\n\t\t}\n\t\tconst rawMode = String(body.mode ?? \"\")\n\t\t\t.trim()\n\t\t\t.toLowerCase();\n\t\tif (rawMode && rawMode !== \"manual\" && rawMode !== \"discovered\") {\n\t\t\treturn c.json(\n\t\t\t\t{ error: \"invalid_mode\", detail: `mode must be 'discovered' or 'manual', got ${rawMode}` },\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tconst mode: \"discovered\" | \"manual\" = rawMode === \"manual\" ? \"manual\" : \"discovered\";\n\t\t// Per-field normalization: distinguish \"caller did not specify\" from\n\t\t// \"caller set empty\". `undefined` = inherit (template); `null` or empty\n\t\t// array = explicit clear; non-empty array = use as-is.\n\t\tconst normalizeOverride = (value: unknown): string[] | null | undefined => {\n\t\t\tif (value === undefined) return undefined;\n\t\t\tif (value === null) return null;\n\t\t\tif (!Array.isArray(value)) return undefined;\n\t\t\tconst cleaned = value\n\t\t\t\t.map((item) => String(item ?? \"\").trim())\n\t\t\t\t.filter((item) => item.length > 0);\n\t\t\treturn cleaned.length === 0 ? null : cleaned;\n\t\t};\n\t\tconst overrideInclude = normalizeOverride(body.projects_include);\n\t\tconst overrideExclude = normalizeOverride(body.projects_exclude);\n\t\tconst scopeOverride =\n\t\t\toverrideInclude === undefined && overrideExclude === undefined\n\t\t\t\t? undefined\n\t\t\t\t: { projects_include: overrideInclude, projects_exclude: overrideExclude };\n\t\tconst store = getStore();\n\n\t\tif (mode === \"manual\") {\n\t\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\t\tconst publicKey = String(body.peer_public_key ?? \"\").trim();\n\t\t\tconst name = String(body.name ?? \"\").trim() || null;\n\t\t\tconst requestedFingerprint = String(body.fingerprint ?? \"\").trim();\n\t\t\tconst addressesInput = Array.isArray(body.peer_addresses) ? body.peer_addresses : [];\n\t\t\tconst addresses = mergeAddresses(\n\t\t\t\t[],\n\t\t\t\taddressesInput.map((item) => String(item ?? \"\").trim()).filter((item) => item.length > 0),\n\t\t\t);\n\t\t\tif (!peerDeviceId || !publicKey) {\n\t\t\t\treturn c.json({ error: \"peer_device_id_and_public_key_required\" }, 400);\n\t\t\t}\n\t\t\tconst fingerprint = requestedFingerprint || fingerprintPublicKey(publicKey);\n\t\t\tif (fingerprintPublicKey(publicKey) !== fingerprint) {\n\t\t\t\treturn c.json({ error: \"fingerprint_mismatch\" }, 400);\n\t\t\t}\n\t\t\tconst manualInclude =\n\t\t\t\toverrideInclude && overrideInclude.length > 0 ? JSON.stringify(overrideInclude) : null;\n\t\t\tconst manualExclude =\n\t\t\t\toverrideExclude && overrideExclude.length > 0 ? JSON.stringify(overrideExclude) : null;\n\t\t\tconst now = new Date().toISOString();\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\t// Wrap the duplicate check + insert in a transaction so two concurrent\n\t\t\t// enrolls for the same peer cannot both clear the check. SQLite\n\t\t\t// serializes transactions on the write lock, so the second one sees\n\t\t\t// the committed row and returns 409 instead of racing past.\n\t\t\ttry {\n\t\t\t\tconst created = store.db.transaction(() => {\n\t\t\t\t\tconst existing = d\n\t\t\t\t\t\t.select({ peer_device_id: schema.syncPeers.peer_device_id })\n\t\t\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t\t\t\t.get();\n\t\t\t\t\tif (existing) return false;\n\t\t\t\t\td.insert(schema.syncPeers)\n\t\t\t\t\t\t.values({\n\t\t\t\t\t\t\tpeer_device_id: peerDeviceId,\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tpinned_fingerprint: fingerprint,\n\t\t\t\t\t\t\tpublic_key: publicKey,\n\t\t\t\t\t\t\taddresses_json: JSON.stringify(addresses),\n\t\t\t\t\t\t\tprojects_include_json: manualInclude,\n\t\t\t\t\t\t\tprojects_exclude_json: manualExclude,\n\t\t\t\t\t\t\tcreated_at: now,\n\t\t\t\t\t\t\tlast_seen_at: now,\n\t\t\t\t\t\t\tdiscovered_via_coordinator_id: null,\n\t\t\t\t\t\t\tdiscovered_via_group_id: null,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.run();\n\t\t\t\t\treturn true;\n\t\t\t\t})();\n\t\t\t\tif (!created) {\n\t\t\t\t\treturn c.json({ error: \"peer_exists\", detail: \"Peer is already enrolled.\" }, 409);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// Primary-key constraint collision is the expected race signal; the\n\t\t\t\t// first writer wins, the second gets \"peer_exists\".\n\t\t\t\tconst msg = error instanceof Error ? error.message.toLowerCase() : \"\";\n\t\t\t\tif (msg.includes(\"unique\") || msg.includes(\"primary key\")) {\n\t\t\t\t\treturn c.json({ error: \"peer_exists\", detail: \"Peer is already enrolled.\" }, 409);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn c.json({\n\t\t\t\tok: true,\n\t\t\t\tpeer_device_id: peerDeviceId,\n\t\t\t\tcreated: true,\n\t\t\t\tupdated: false,\n\t\t\t\tname,\n\t\t\t\tgroup_id: null,\n\t\t\t});\n\t\t}\n\n\t\t// Discovered mode calls out to the coordinator for reciprocal approval,\n\t\t// so it needs the admin secret. Manual mode never leaves this process.\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 peerDeviceId = String(body.peer_device_id ?? body.discovered_device_id ?? \"\").trim();\n\t\tconst fingerprint = String(body.fingerprint ?? \"\").trim();\n\t\tif (!peerDeviceId || !fingerprint) {\n\t\t\treturn c.json({ error: \"peer_device_id_and_fingerprint_required\" }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst result = await acceptDiscoveredPeer(store, {\n\t\t\t\tpeerDeviceId,\n\t\t\t\tfingerprint,\n\t\t\t\texpectedGroupId: rawGroupId,\n\t\t\t\tscopeOverride,\n\t\t\t});\n\t\t\tif (result.ok) {\n\t\t\t\treturn c.json(result);\n\t\t\t}\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: result.error,\n\t\t\t\t\tdetail: result.detail,\n\t\t\t\t\t...(result.reason ? { reason: result.reason } : {}),\n\t\t\t\t},\n\t\t\t\tresult.status as 400 | 404 | 409,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// acceptDiscoveredPeer shells out to the coordinator for reciprocal\n\t\t\t// approval and can throw on timeout / network / auth failures. Map\n\t\t\t// those to a structured 502 so clients get the same shape as the\n\t\t\t// legacy /api/sync/peers/accept-discovered path.\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\t502,\n\t\t\t);\n\t\t}\n\t});\n\n\t// Local-only preferences for a coordinator group — project-scope template\n\t// + auto-seed toggle applied when peers are enrolled through the group.\n\t// See docs/plans/2026-04-22-multi-team-coordinator-groups-design.md.\n\t// Local-only preferences — these rows live in the viewer's own DB and never\n\t// cross the wire to the coordinator. No admin-secret gate: the admin secret\n\t// authorizes remote coordinator mutations, not local settings.\n\tapp.get(\"/api/coordinator/admin/groups/:group_id/preferences\", (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\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tconst coordinatorId = status.coordinator_url;\n\t\tif (!coordinatorId) return c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\tconst store = getStore();\n\t\tconst existing = getCoordinatorGroupPreference(store.db, coordinatorId, groupId);\n\t\tif (existing) return c.json({ preferences: existing, status });\n\t\treturn c.json({\n\t\t\tpreferences: {\n\t\t\t\tcoordinator_id: coordinatorId,\n\t\t\t\tgroup_id: groupId,\n\t\t\t\tprojects_include: null,\n\t\t\t\tprojects_exclude: null,\n\t\t\t\tauto_seed_scope: true,\n\t\t\t\tdefault_space_scope_id: null,\n\t\t\t\tauto_grant_default_space_on_join: false,\n\t\t\t\tupdated_at: null,\n\t\t\t},\n\t\t\tstatus,\n\t\t});\n\t});\n\n\tapp.put(\"/api/coordinator/admin/groups/:group_id/preferences\", 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\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tconst coordinatorId = status.coordinator_url;\n\t\tif (!coordinatorId) return c.json({ error: \"coordinator_not_configured\", 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 normalizeList = (value: unknown): string[] | null | undefined => {\n\t\t\tif (value === undefined) return undefined;\n\t\t\tif (value === null) return null;\n\t\t\tif (!Array.isArray(value)) return undefined;\n\t\t\tconst cleaned = value\n\t\t\t\t.map((item) => String(item ?? \"\").trim())\n\t\t\t\t.filter((item) => item.length > 0);\n\t\t\treturn cleaned.length === 0 ? null : cleaned;\n\t\t};\n\t\tconst autoSeed = typeof body.auto_seed_scope === \"boolean\" ? body.auto_seed_scope : undefined;\n\t\tconst autoGrantDefaultSpace =\n\t\t\ttypeof body.auto_grant_default_space_on_join === \"boolean\"\n\t\t\t\t? body.auto_grant_default_space_on_join\n\t\t\t\t: undefined;\n\t\tconst defaultSpaceScopeId =\n\t\t\tbody.default_space_scope_id === undefined\n\t\t\t\t? undefined\n\t\t\t\t: optionalViewerString(body, \"default_space_scope_id\");\n\t\tif (autoGrantDefaultSpace === true && !defaultSpaceScopeId) {\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: \"default_space_scope_id_required_for_auto_grant\",\n\t\t\t\t\tstatus,\n\t\t\t\t},\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tconst store = getStore();\n\t\ttry {\n\t\t\tconst preferences = upsertCoordinatorGroupPreference(store.db, {\n\t\t\t\tcoordinator_id: coordinatorId,\n\t\t\t\tgroup_id: groupId,\n\t\t\t\tprojects_include: normalizeList(body.projects_include),\n\t\t\t\tprojects_exclude: normalizeList(body.projects_exclude),\n\t\t\t\tauto_seed_scope: autoSeed,\n\t\t\t\tdefault_space_scope_id: defaultSpaceScopeId,\n\t\t\t\tauto_grant_default_space_on_join: autoGrantDefaultSpace,\n\t\t\t});\n\t\t\treturn c.json({ preferences, status });\n\t\t} catch (error) {\n\t\t\tconst msg = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: msg, 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(\"/assets/*\", async (c, next) => {\n\t\tc.header(\"Cache-Control\", \"no-cache\");\n\t\tawait next();\n\t});\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\tc.header(\"Cache-Control\", \"no-store\");\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 REMOVED_CONFIG_KEYS = new Set<string>([\"observer_rich_openai_use_responses\"]);\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_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_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 withoutRemovedConfigKeys(configData: ConfigData): ConfigData {\n\tconst next = { ...configData };\n\tfor (const key of REMOVED_CONFIG_KEYS) {\n\t\tdelete next[key];\n\t}\n\treturn next;\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\") {\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 = withoutRemovedConfigKeys(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 = withoutRemovedConfigKeys(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 { MemoryFilters, MemoryStore } from \"@codemem/core\";\nimport {\n\tbuildFilterClausesWithContext,\n\tcanonicalMemoryKind,\n\tfromJson,\n\tisSummaryLikeMemory as isCoreSummaryLikeMemory,\n\tparseStrictInteger,\n\tschema,\n} from \"@codemem/core\";\nimport { eq, inArray } 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 buildViewerMemoryFilters(store: MemoryStore, filters?: MemoryFilters | null) {\n\treturn buildFilterClausesWithContext(filters, {\n\t\tactorId: store.actorId,\n\t\tdeviceId: store.deviceId,\n\t\tenforceScopeVisibility: true,\n\t});\n}\n\nfunction countVisibleMemoryRows(store: MemoryStore, filters?: MemoryFilters | null): number {\n\tconst filterResult = buildViewerMemoryFilters(store, filters);\n\tconst clauses = [\"memory_items.active = 1\", ...filterResult.clauses];\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\tconst row = store.db\n\t\t.prepare(`SELECT COUNT(*) AS total FROM ${from} WHERE ${clauses.join(\" AND \")}`)\n\t\t.get(...filterResult.params) as Record<string, unknown> | undefined;\n\treturn Number(row?.total ?? 0);\n}\n\nfunction summaryLikeSqlPredicate(): string {\n\treturn `(\n\t\tLOWER(TRIM(COALESCE(memory_items.kind, ''))) = 'session_summary'\n\t\tOR (\n\t\t\tjson_valid(COALESCE(memory_items.metadata_json, ''))\n\t\t\tAND (\n\t\t\t\tCOALESCE(json_extract(memory_items.metadata_json, '$.is_summary') = 1, 0)\n\t\t\t\tOR LOWER(TRIM(COALESCE(json_extract(memory_items.metadata_json, '$.source'), ''))) = 'observer_summary'\n\t\t\t)\n\t\t)\n\t)`;\n}\n\nfunction countVisibleObservationRows(store: MemoryStore, filters?: MemoryFilters | null): number {\n\tconst filterResult = buildViewerMemoryFilters(store, filters);\n\tconst clauses = [\n\t\t\"memory_items.active = 1\",\n\t\t`NOT ${summaryLikeSqlPredicate()}`,\n\t\t...filterResult.clauses,\n\t];\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\tconst row = store.db\n\t\t.prepare(`SELECT COUNT(*) AS total FROM ${from} WHERE ${clauses.join(\" AND \")}`)\n\t\t.get(...filterResult.params) as Record<string, unknown> | undefined;\n\treturn Number(row?.total ?? 0);\n}\n\nfunction sessionAllowsArtifactAccess(store: MemoryStore, sessionId: number): boolean {\n\tconst visibleCount = countVisibleMemoryRows(store, { session_id: sessionId });\n\tif (visibleCount === 0) return false;\n\tconst row = store.db\n\t\t.prepare(\n\t\t\t`SELECT COUNT(*) AS total FROM memory_items\n\t\t\t WHERE session_id = ? AND active = 1`,\n\t\t)\n\t\t.get(sessionId) as Record<string, unknown> | undefined;\n\treturn visibleCount === Number(row?.total ?? 0);\n}\n\nfunction countVisiblePromptRows(store: MemoryStore, project?: string | null): number {\n\tconst filterResult = buildViewerMemoryFilters(store, null);\n\tconst clauses = [\n\t\t\"user_prompts.session_id IS NOT NULL\",\n\t\t`EXISTS (\n\t\t\tSELECT 1 FROM memory_items\n\t\t\tWHERE memory_items.session_id = user_prompts.session_id\n\t\t\t AND memory_items.active = 1\n\t\t\t AND ${filterResult.clauses.join(\" AND \")}\n\t\t)`,\n\t];\n\tconst params: unknown[] = [...filterResult.params];\n\tif (project) {\n\t\tclauses.unshift(\"user_prompts.project = ?\");\n\t\tparams.unshift(project);\n\t}\n\tconst row = store.db\n\t\t.prepare(`SELECT COUNT(*) AS total FROM user_prompts WHERE ${clauses.join(\" AND \")}`)\n\t\t.get(...params) as Record<string, unknown> | undefined;\n\treturn Number(row?.total ?? 0);\n}\n\nfunction countVisibleArtifactRows(store: MemoryStore, project?: string | null): number {\n\tconst filterResult = buildViewerMemoryFilters(store, null);\n\tconst clauses = [\n\t\t`EXISTS (\n\t\t\tSELECT 1 FROM memory_items\n\t\t\tWHERE memory_items.session_id = artifacts.session_id\n\t\t\t AND memory_items.active = 1\n\t\t\t AND ${filterResult.clauses.join(\" AND \")}\n\t\t)`,\n\t];\n\tconst params: unknown[] = [...filterResult.params];\n\tconst from = project\n\t\t? \"artifacts JOIN sessions ON sessions.id = artifacts.session_id\"\n\t\t: \"artifacts\";\n\tif (project) {\n\t\tclauses.unshift(\"sessions.project = ?\");\n\t\tparams.unshift(project);\n\t}\n\tconst row = store.db\n\t\t.prepare(`SELECT COUNT(*) AS total FROM ${from} WHERE ${clauses.join(\" AND \")}`)\n\t\t.get(...params) as Record<string, unknown> | undefined;\n\treturn Number(row?.total ?? 0);\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: MemoryFilters = {};\n\tif (options.project) filters.project = options.project;\n\tif (options.scope) filters.ownership_scope = options.scope;\n\n\tconst filterResult = buildViewerMemoryFilters(store, filters);\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 filterResult = buildViewerMemoryFilters(store, null);\n\t\t\tconst clauses = [\n\t\t\t\t\"memory_items.session_id = sessions.id\",\n\t\t\t\t\"memory_items.active = 1\",\n\t\t\t\t...filterResult.clauses,\n\t\t\t];\n\t\t\tconst rows = store.db\n\t\t\t\t.prepare(\n\t\t\t\t\t`SELECT sessions.* FROM sessions\n\t\t\t\t\t WHERE EXISTS (SELECT 1 FROM memory_items WHERE ${clauses.join(\" AND \")})\n\t\t\t\t\t ORDER BY sessions.started_at DESC\n\t\t\t\t\t LIMIT ?`,\n\t\t\t\t)\n\t\t\t\t.all(...filterResult.params, limit) as Record<string, unknown>[];\n\t\t\tconst items = rows.map((row) => ({\n\t\t\t\t...row,\n\t\t\t\tmetadata_json: fromJson((row.metadata_json as string | null | undefined) ?? null),\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 filterResult = buildViewerMemoryFilters(store, null);\n\t\t\tconst clauses = [\n\t\t\t\t\"memory_items.session_id = sessions.id\",\n\t\t\t\t\"memory_items.active = 1\",\n\t\t\t\t\"sessions.project IS NOT NULL\",\n\t\t\t\t...filterResult.clauses,\n\t\t\t];\n\t\t\tconst rows = store.db\n\t\t\t\t.prepare(\n\t\t\t\t\t`SELECT DISTINCT sessions.project AS project FROM sessions\n\t\t\t\t\t JOIN memory_items ON memory_items.session_id = sessions.id\n\t\t\t\t\t WHERE ${clauses.join(\" AND \")}`,\n\t\t\t\t)\n\t\t\t\t.all(...filterResult.params) as Record<string, unknown>[];\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\tlet prompts: number;\n\t\t\tlet artifacts: number;\n\t\t\tlet memories: number;\n\t\t\tlet observations: number;\n\t\t\tif (project) {\n\t\t\t\tprompts = countVisiblePromptRows(store, project);\n\t\t\t\tartifacts = countVisibleArtifactRows(store, project);\n\t\t\t\tmemories = countVisibleMemoryRows(store, { project });\n\t\t\t\tobservations = countVisibleObservationRows(store, { project });\n\t\t\t} else {\n\t\t\t\tprompts = countVisiblePromptRows(store);\n\t\t\t\tartifacts = countVisibleArtifactRows(store);\n\t\t\t\tmemories = countVisibleMemoryRows(store);\n\t\t\t\tobservations = countVisibleObservationRows(store);\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: MemoryFilters = {};\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\tif (!sessionAllowsArtifactAccess(store, sessionId)) {\n\t\t\t\treturn c.json({ error: \"session not found\" }, 404);\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\tif (!store.get(memoryId)) {\n\t\t\treturn c.json({ error: \"memory not found\" }, 404);\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/project\n\tapp.post(\"/api/memories/project\", 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 project = String(body.project ?? \"\").trim();\n\t\tif (!project) {\n\t\t\treturn c.json({ error: \"project must be a non-empty string\" }, 400);\n\t\t}\n\t\tif (!store.get(memoryId)) {\n\t\t\treturn c.json({ error: \"memory not found\" }, 404);\n\t\t}\n\t\ttry {\n\t\t\tconst result = store.moveMemoryProject(memoryId, project);\n\t\t\treturn c.json(result);\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\t\tif (!store.get(memoryId)) {\n\t\t\treturn c.json({ error: \"memory not found\" }, 404);\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 {\n\tbuildFilterClausesWithContext,\n\tlistMaintenanceJobs,\n\ttype MemoryStore,\n\tVERSION,\n} 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\nconst MEMORY_ID_METADATA_KEYS = [\"pack_item_ids\", \"added_ids\", \"removed_ids\", \"retained_ids\"];\n\ntype UsageRow = {\n\tid: number;\n\tsession_id: number | null;\n\tevent: string;\n\ttokens_read: number;\n\ttokens_written: number;\n\ttokens_saved: number;\n\tcreated_at: string;\n\tmetadata_json: Record<string, unknown> | null;\n};\n\ntype UsageVisibility = {\n\tvisibleMemoryIds: Set<number>;\n\tvisibleSessionIds: Set<number>;\n};\n\nfunction toUsageRow(\n\trow: Record<string, unknown>,\n\tmetadata: Record<string, unknown> | null,\n): UsageRow {\n\treturn {\n\t\tid: Number(row.id ?? 0),\n\t\tsession_id: row.session_id == null ? null : Number(row.session_id),\n\t\tevent: String(row.event ?? \"pack\"),\n\t\ttokens_read: Number(row.tokens_read ?? 0),\n\t\ttokens_written: Number(row.tokens_written ?? 0),\n\t\ttokens_saved: Number(row.tokens_saved ?? 0),\n\t\tcreated_at: String(row.created_at ?? \"\"),\n\t\tmetadata_json: metadata,\n\t};\n}\n\nfunction metadataMemoryIds(value: unknown): number[] {\n\tif (!Array.isArray(value)) return [];\n\treturn value\n\t\t.map((item) => (typeof item === \"number\" ? item : Number(item)))\n\t\t.filter((item) => Number.isInteger(item) && item > 0);\n}\n\nfunction chunkNumbers(values: number[], chunkSize = 500): number[][] {\n\tconst chunks: number[][] = [];\n\tfor (let start = 0; start < values.length; start += chunkSize) {\n\t\tchunks.push(values.slice(start, start + chunkSize));\n\t}\n\treturn chunks;\n}\n\nfunction visibleMemoryIdSet(store: MemoryStore, memoryIds: Set<number>): Set<number> {\n\tif (memoryIds.size === 0) return new Set();\n\tconst filterResult = buildFilterClausesWithContext(null, {\n\t\tactorId: store.actorId,\n\t\tdeviceId: store.deviceId,\n\t\tenforceScopeVisibility: true,\n\t});\n\tconst visibleIds = new Set<number>();\n\tfor (const chunk of chunkNumbers([...memoryIds])) {\n\t\tconst placeholders = chunk.map(() => \"?\").join(\", \");\n\t\tconst clauses = [\n\t\t\t\"memory_items.active = 1\",\n\t\t\t`memory_items.id IN (${placeholders})`,\n\t\t\t...filterResult.clauses,\n\t\t];\n\t\tconst rows = store.db\n\t\t\t.prepare(`SELECT memory_items.id FROM memory_items WHERE ${clauses.join(\" AND \")}`)\n\t\t\t.all(...chunk, ...filterResult.params) as Array<{ id: number }>;\n\t\tfor (const row of rows) visibleIds.add(Number(row.id));\n\t}\n\treturn visibleIds;\n}\n\nfunction visibleSessionIdSet(store: MemoryStore, sessionIds: Set<number>): Set<number> {\n\tif (sessionIds.size === 0) return new Set();\n\tconst filterResult = buildFilterClausesWithContext(null, {\n\t\tactorId: store.actorId,\n\t\tdeviceId: store.deviceId,\n\t\tenforceScopeVisibility: true,\n\t});\n\tconst visibleIds = new Set<number>();\n\tfor (const chunk of chunkNumbers([...sessionIds])) {\n\t\tconst placeholders = chunk.map(() => \"?\").join(\", \");\n\t\tconst clauses = [\n\t\t\t\"memory_items.active = 1\",\n\t\t\t`memory_items.session_id IN (${placeholders})`,\n\t\t\t...filterResult.clauses,\n\t\t];\n\t\tconst rows = store.db\n\t\t\t.prepare(\n\t\t\t\t`SELECT DISTINCT memory_items.session_id AS session_id\n\t\t\t\t FROM memory_items\n\t\t\t\t WHERE ${clauses.join(\" AND \")}`,\n\t\t\t)\n\t\t\t.all(...chunk, ...filterResult.params) as Array<{ session_id: number | null }>;\n\t\tfor (const row of rows) {\n\t\t\tif (typeof row.session_id === \"number\") visibleIds.add(row.session_id);\n\t\t}\n\t}\n\treturn visibleIds;\n}\n\nfunction buildUsageVisibility(store: MemoryStore, rows: UsageRow[]): UsageVisibility {\n\tconst memoryIds = new Set<number>();\n\tconst sessionIds = new Set<number>();\n\tfor (const row of rows) {\n\t\tif (typeof row.session_id === \"number\") sessionIds.add(row.session_id);\n\t\tfor (const key of MEMORY_ID_METADATA_KEYS) {\n\t\t\tfor (const memoryId of metadataMemoryIds(row.metadata_json?.[key])) {\n\t\t\t\tmemoryIds.add(memoryId);\n\t\t\t}\n\t\t}\n\t}\n\treturn {\n\t\tvisibleMemoryIds: visibleMemoryIdSet(store, memoryIds),\n\t\tvisibleSessionIds: visibleSessionIdSet(store, sessionIds),\n\t};\n}\n\nfunction usageRowVisible(row: UsageRow, visibility: UsageVisibility): boolean {\n\tconst rowSessionVisible =\n\t\trow.session_id == null || visibility.visibleSessionIds.has(row.session_id);\n\tconst packItemIds = row.metadata_json?.pack_item_ids;\n\tif (Array.isArray(packItemIds)) {\n\t\tif (packItemIds.length === 0) {\n\t\t\treturn row.session_id != null && visibility.visibleSessionIds.has(row.session_id);\n\t\t}\n\t\treturn (\n\t\t\trowSessionVisible &&\n\t\t\tmetadataMemoryIds(packItemIds).some((memoryId) => visibility.visibleMemoryIds.has(memoryId))\n\t\t);\n\t}\n\treturn row.session_id != null && visibility.visibleSessionIds.has(row.session_id);\n}\n\nfunction sanitizePackUsageMetadata(\n\tmetadata: Record<string, unknown> | null,\n\tvisibility: UsageVisibility,\n): Record<string, unknown> | null {\n\tif (!metadata) return null;\n\tconst sanitized = { ...metadata };\n\tfor (const key of MEMORY_ID_METADATA_KEYS) {\n\t\tif (Array.isArray(sanitized[key])) {\n\t\t\tsanitized[key] = metadataMemoryIds(sanitized[key]).filter((memoryId) =>\n\t\t\t\tvisibility.visibleMemoryIds.has(memoryId),\n\t\t\t);\n\t\t}\n\t}\n\treturn sanitized;\n}\n\nfunction summarizeUsageEvents(rows: UsageRow[]): Record<string, unknown>[] {\n\tconst byEvent = new Map<\n\t\tstring,\n\t\t{\n\t\t\tevent: string;\n\t\t\ttotal_tokens_read: number;\n\t\t\ttotal_tokens_written: number;\n\t\t\ttotal_tokens_saved: number;\n\t\t\tcount: number;\n\t\t}\n\t>();\n\tfor (const row of rows) {\n\t\tconst summary = byEvent.get(row.event) ?? {\n\t\t\tevent: row.event,\n\t\t\ttotal_tokens_read: 0,\n\t\t\ttotal_tokens_written: 0,\n\t\t\ttotal_tokens_saved: 0,\n\t\t\tcount: 0,\n\t\t};\n\t\tsummary.total_tokens_read += row.tokens_read;\n\t\tsummary.total_tokens_written += row.tokens_written;\n\t\tsummary.total_tokens_saved += row.tokens_saved;\n\t\tsummary.count += 1;\n\t\tbyEvent.set(row.event, summary);\n\t}\n\treturn [...byEvent.values()].sort((a, b) => a.event.localeCompare(b.event));\n}\n\nfunction totalUsageEvents(rows: UsageRow[]): Record<string, unknown> {\n\treturn rows.reduce(\n\t\t(acc, row) => ({\n\t\t\ttokens_read: Number(acc.tokens_read) + row.tokens_read,\n\t\t\ttokens_written: Number(acc.tokens_written) + row.tokens_written,\n\t\t\ttokens_saved: Number(acc.tokens_saved) + row.tokens_saved,\n\t\t\tcount: Number(acc.count) + 1,\n\t\t}),\n\t\t{ tokens_read: 0, tokens_written: 0, tokens_saved: 0, count: 0 } as Record<string, unknown>,\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\t// Keep completed jobs visible in /api/stats for a short window after\n\t// finished_at so the health UI has a chance to render success confirmation\n\t// for fast-completing backfills (often <1s). Failed jobs stay indefinitely.\n\tconst RECENTLY_COMPLETED_WINDOW_MS = 120_000;\n\n\tapp.get(\"/api/stats\", (c) => {\n\t\tconst store = getStore();\n\t\tconst jobs = listMaintenanceJobs(store.db);\n\t\tconst now = Date.now();\n\t\tconst surfacedJobs = sortActiveMaintenanceJobs(\n\t\t\tjobs.filter((job) => {\n\t\t\t\tif (job.status === \"pending\" || job.status === \"running\" || job.status === \"failed\") {\n\t\t\t\t\treturn true;\n\t\t\t\t}\n\t\t\t\tif (job.status === \"completed\" && job.finished_at) {\n\t\t\t\t\tconst finished = Date.parse(job.finished_at);\n\t\t\t\t\tif (Number.isFinite(finished) && now - finished <= RECENTLY_COMPLETED_WINDOW_MS) {\n\t\t\t\t\t\treturn true;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\treturn false;\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\tfinished_at: job.finished_at,\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: surfacedJobs,\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 loadUsageRows = (project?: string | null): UsageRow[] => {\n\t\t\t\tconst rows = project\n\t\t\t\t\t? (store.db\n\t\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t\t`SELECT usage_events.id, usage_events.session_id, usage_events.event,\n\t\t\t\t\t\t\t\t\tusage_events.tokens_read, usage_events.tokens_written, usage_events.tokens_saved,\n\t\t\t\t\t\t\t\t\tusage_events.created_at, usage_events.metadata_json\n\t\t\t\t\t\t\t\t FROM usage_events\n\t\t\t\t\t\t\t\t JOIN sessions ON sessions.id = usage_events.session_id\n\t\t\t\t\t\t\t\t WHERE sessions.project = ?\n\t\t\t\t\t\t\t\t ORDER BY usage_events.created_at DESC`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.all(project) as Record<string, unknown>[])\n\t\t\t\t\t: (store.db\n\t\t\t\t\t\t\t.prepare(\n\t\t\t\t\t\t\t\t`SELECT id, session_id, event, tokens_read, tokens_written, tokens_saved,\n\t\t\t\t\t\t\t\t\tcreated_at, metadata_json\n\t\t\t\t\t\t\t\t FROM usage_events\n\t\t\t\t\t\t\t\t ORDER BY created_at DESC`,\n\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t.all() as Record<string, unknown>[]);\n\t\t\t\treturn rows.map((row) => toUsageRow(row, parseMetadataJson(row.metadata_json)));\n\t\t\t};\n\t\t\tconst loadedGlobalRows = loadUsageRows();\n\t\t\tconst globalVisibility = buildUsageVisibility(store, loadedGlobalRows);\n\t\t\tconst globalRows = loadedGlobalRows.filter((row) => usageRowVisible(row, globalVisibility));\n\t\t\tconst loadedFilteredRows = projectFilter ? loadUsageRows(projectFilter) : null;\n\t\t\tconst filteredVisibility = loadedFilteredRows\n\t\t\t\t? buildUsageVisibility(store, loadedFilteredRows)\n\t\t\t\t: null;\n\t\t\tconst filteredRows = loadedFilteredRows\n\t\t\t\t? loadedFilteredRows.filter((row) =>\n\t\t\t\t\t\tusageRowVisible(row, filteredVisibility ?? globalVisibility),\n\t\t\t\t\t)\n\t\t\t\t: null;\n\t\t\tconst eventsGlobal = summarizeUsageEvents(globalRows);\n\t\t\tconst totalsGlobal = totalUsageEvents(globalRows);\n\t\t\tconst eventsFiltered = filteredRows ? summarizeUsageEvents(filteredRows) : null;\n\t\t\tconst totalsFiltered = filteredRows ? totalUsageEvents(filteredRows) : null;\n\t\t\tconst recentVisibility = filteredVisibility ?? globalVisibility;\n\t\t\tconst recentPacks = (filteredRows ?? globalRows)\n\t\t\t\t.filter((row) => row.event === \"pack\")\n\t\t\t\t.slice(0, 10)\n\t\t\t\t.map((row) => ({\n\t\t\t\t\t...row,\n\t\t\t\t\tmetadata_json: sanitizePackUsageMetadata(row.metadata_json, recentVisibility),\n\t\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 { networkInterfaces } from \"node:os\";\nimport { dirname, join } from \"node:path\";\nimport type {\n\tCoordinatorBootstrapGrantVerification,\n\tCoordinatorScope,\n\tCoordinatorScopeMembership,\n\tMaintenanceJobSnapshot,\n\tMemoryStore,\n\tProjectScopeGuardrailWarning,\n\tReplicationOp,\n\tSemanticIndexDiagnostics,\n} from \"@codemem/core\";\nimport {\n\taddSyncScopeToBoundary,\n\tanalyzeProjectScopeMappingChangeGuardrails,\n\tapplyReplicationOps,\n\tbuildBaseUrl,\n\tcanonicalWorkspaceIdentity,\n\tcleanupNonces,\n\tcoordinatorArchiveGroupAction,\n\tcoordinatorCreateGroupAction,\n\tcoordinatorCreateInviteAction,\n\tcoordinatorCreateScopeAction,\n\tcoordinatorDisableDeviceAction,\n\tcoordinatorEnableDeviceAction,\n\tcoordinatorGrantScopeMembershipAction,\n\tcoordinatorImportInviteAction,\n\tcoordinatorListBootstrapGrantsAction,\n\tcoordinatorListDevicesAction,\n\tcoordinatorListGroupsAction,\n\tcoordinatorListJoinRequestsAction,\n\tcoordinatorListScopeMembershipsAction,\n\tcoordinatorListScopesAction,\n\tcoordinatorRemoveDeviceAction,\n\tcoordinatorRenameDeviceAction,\n\tcoordinatorRenameGroupAction,\n\tcoordinatorReviewJoinRequestAction,\n\tcoordinatorRevokeBootstrapGrantAction,\n\tcoordinatorRevokeScopeMembershipAction,\n\tcoordinatorStatusSnapshot,\n\tcoordinatorUnarchiveGroupAction,\n\tcoordinatorUpdateScopeAction,\n\tcreateCoordinatorReciprocalApproval,\n\tDEFAULT_TIME_WINDOW_S,\n\tdefaultSpaceScopeIdForGroup,\n\tdeleteProjectScopeSettingsMapping,\n\tensureDeviceIdentity,\n\textractReplicationOps,\n\ttype FilterReplicationSkipped,\n\tfilterReplicationOpsForSyncWithStatus,\n\tfingerprintPublicKey,\n\tformatHostPort,\n\tgetCoordinatorGroupPreference,\n\tgetSemanticIndexDiagnostics,\n\tgetSyncResetState,\n\ttype InboundScopeRejectionPeerSummary,\n\tisScopedSyncCapability,\n\tLEGACY_SHARED_REVIEW_SCOPE_ID,\n\tLOCAL_DEFAULT_SCOPE_ID,\n\tLOCAL_SYNC_CAPABILITY,\n\tlistAuthorizedScopesForPeer,\n\tlistCoordinatorJoinRequests,\n\tlistInboundScopeRejections,\n\tlistMaintenanceJobs,\n\tlistPerPeerScopeSyncState,\n\tlistProjectScopeCandidates,\n\tlistProjectScopeInventory,\n\tlistProjectScopeSettingsMappings,\n\tlistSharingDomainSettingsScopes,\n\tloadMemorySnapshotPageForPeer,\n\tloadReplicationOpsForPeer,\n\tlookupCoordinatorPeers,\n\tmergeAddresses,\n\tnegotiateSyncCapability,\n\tnormalizeAddress,\n\tnormalizeSyncCapability,\n\tparseSyncScopeRequest,\n\tpersonalScopeGrantStatusForPeer,\n\treadCodememConfigFile,\n\treadCoordinatorSyncConfig,\n\treassignProjectScopeInventoryProject,\n\trecordNonce,\n\trejectInboundScopeFailures,\n\trequestJson,\n\trunSyncPass,\n\tSYNC_CAPABILITY_HEADER,\n\tSYNC_SCOPE_QUERY_PARAM,\n\tschema,\n\tsummarizeInboundScopeRejections,\n\tsyncScopeResetRequiredPayload,\n\tupdatePeerAddresses,\n\tupsertCoordinatorGroupPreference,\n\tupsertProjectScopeSettingsMapping,\n\tverifySignature,\n\twriteCodememConfigFile,\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\ntype SafeSkippedSyncDetail = Pick<\n\tFilterReplicationSkipped,\n\t\"reason\" | \"skipped_count\" | \"scope_id\" | \"project\" | \"visibility\"\n>;\n\nfunction safeSkippedSyncDetail(\n\tdetail: FilterReplicationSkipped | null | undefined,\n): SafeSkippedSyncDetail | null {\n\tif (!detail) return null;\n\treturn {\n\t\treason: detail.reason,\n\t\tskipped_count: detail.skipped_count,\n\t\tscope_id: detail.scope_id ?? null,\n\t\tproject: detail.project ?? null,\n\t\tvisibility: detail.visibility ?? null,\n\t};\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\n/**\n * Attempt to decode a pasted string as a device-pairing payload.\n *\n * Returns:\n * - `{ kind: \"pair\", ... }` when the payload base64-decodes to JSON with\n * the expected pairing shape AND the fingerprint matches the public\n * key.\n * - `{ kind: \"invalid-pair\", error }` when the payload looked like a\n * pairing payload but failed validation — the caller should 400 this\n * rather than falling back to coordinator-invite handling.\n * - `null` when the string is not a pairing payload at all.\n */\nfunction tryParsePairingPayload(value: string):\n\t| {\n\t\t\tkind: \"pair\";\n\t\t\tdevice_id: string;\n\t\t\tfingerprint: string;\n\t\t\tpublic_key: string;\n\t\t\taddresses: string[];\n\t }\n\t| { kind: \"invalid-pair\"; error: string }\n\t| null {\n\t// Accept both shapes the CLI can emit:\n\t// - raw JSON (`codemem sync pair --payload-only`)\n\t// - base64-encoded JSON (the inner blob inside the shell pipe wrapper)\n\tlet parsed: Record<string, unknown>;\n\tif (value.trimStart().startsWith(\"{\")) {\n\t\ttry {\n\t\t\tparsed = JSON.parse(value) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t} else {\n\t\tlet decoded: string;\n\t\ttry {\n\t\t\tdecoded = Buffer.from(value, \"base64\").toString(\"utf8\");\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t\tif (!decoded?.trimStart().startsWith(\"{\")) return null;\n\t\ttry {\n\t\t\tparsed = JSON.parse(decoded) as Record<string, unknown>;\n\t\t} catch {\n\t\t\treturn null;\n\t\t}\n\t}\n\tconst deviceId = String(parsed.device_id ?? \"\").trim();\n\tconst fingerprint = String(parsed.fingerprint ?? \"\").trim();\n\tconst publicKey = String(parsed.public_key ?? \"\").trim();\n\t// If the JSON doesn't carry any of the pairing discriminators, treat\n\t// it as a different kind of payload (e.g. a coordinator invite happened\n\t// to be JSON-encoded directly). Let the caller keep trying.\n\tif (!deviceId && !fingerprint && !publicKey) return null;\n\tconst rawAddresses = Array.isArray(parsed.addresses) ? parsed.addresses : [];\n\tconst addresses = rawAddresses\n\t\t.filter((item): item is string => typeof item === \"string\" && item.trim().length > 0)\n\t\t.map((item) => item.trim());\n\tif (!deviceId || !fingerprint || !publicKey || addresses.length === 0) {\n\t\treturn {\n\t\t\tkind: \"invalid-pair\",\n\t\t\terror: \"Pairing payload missing device_id, fingerprint, public_key, or addresses\",\n\t\t};\n\t}\n\tif (fingerprintPublicKey(publicKey) !== fingerprint) {\n\t\treturn { kind: \"invalid-pair\", error: \"Pairing payload fingerprint mismatch\" };\n\t}\n\treturn {\n\t\tkind: \"pair\",\n\t\tdevice_id: deviceId,\n\t\tfingerprint,\n\t\tpublic_key: publicKey,\n\t\taddresses,\n\t};\n}\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\nasync function ensureDefaultSpaceForTeam(opts: {\n\tstore: MemoryStore;\n\tconfig: ReturnType<typeof readCoordinatorSyncConfig>;\n\tgroupId: string;\n\tdisplayName: string | null;\n}): Promise<{\n\tscope: CoordinatorScope | null;\n\tmembership: CoordinatorScopeMembership | null;\n\tpreferences: ReturnType<typeof upsertCoordinatorGroupPreference>;\n}> {\n\tconst coordinatorId = opts.config.syncCoordinatorUrl || null;\n\tif (!coordinatorId) throw new Error(\"coordinator_not_configured\");\n\tconst scopeId = defaultSpaceScopeIdForGroup(opts.groupId);\n\tconst label = opts.displayName || opts.groupId;\n\tconst existingScopes = await coordinatorListScopesAction({\n\t\tgroupId: opts.groupId,\n\t\tincludeInactive: false,\n\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t});\n\tconst existingScope = existingScopes.find((scope) => scope.scope_id === scopeId) ?? null;\n\tconst scope =\n\t\texistingScope ??\n\t\t(await coordinatorCreateScopeAction({\n\t\t\tgroupId: opts.groupId,\n\t\t\tscopeId,\n\t\t\tlabel,\n\t\t\tkind: \"team_default\",\n\t\t\tauthorityType: \"coordinator\",\n\t\t\tcoordinatorId,\n\t\t\tmembershipEpoch: 1,\n\t\t\tstatus: \"active\",\n\t\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t\t}));\n\tconst [deviceId] = ensureDeviceIdentity(opts.store.db, { keysDir: syncKeysDir() });\n\tconst membership = await coordinatorGrantScopeMembershipAction({\n\t\tgroupId: opts.groupId,\n\t\tscopeId,\n\t\tdeviceId,\n\t\trole: \"admin\",\n\t\tmembershipEpoch: 1,\n\t\tcoordinatorId,\n\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t});\n\tconst preferences = upsertCoordinatorGroupPreference(opts.store.db, {\n\t\tcoordinator_id: coordinatorId,\n\t\tgroup_id: opts.groupId,\n\t\tdefault_space_scope_id: scopeId,\n\t\tauto_grant_default_space_on_join: true,\n\t});\n\treturn { scope, membership, preferences };\n}\n\nasync function maybeGrantDefaultSpaceOnJoin(opts: {\n\tstore: MemoryStore;\n\tconfig: ReturnType<typeof readCoordinatorSyncConfig>;\n\tgroupId: string;\n\tdeviceId: string;\n}): Promise<CoordinatorScopeMembership | null> {\n\tconst coordinatorId = opts.config.syncCoordinatorUrl || null;\n\tif (!coordinatorId) return null;\n\tconst preferences = getCoordinatorGroupPreference(opts.store.db, coordinatorId, opts.groupId);\n\tif (!preferences?.auto_grant_default_space_on_join) return null;\n\tconst scopeId = preferences.default_space_scope_id?.trim();\n\tif (!scopeId) return null;\n\tif (scopeId !== defaultSpaceScopeIdForGroup(opts.groupId)) return null;\n\tconst scopes = await coordinatorListScopesAction({\n\t\tgroupId: opts.groupId,\n\t\tincludeInactive: false,\n\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t});\n\tconst defaultScope = scopes.find((scope) => scope.scope_id === scopeId) ?? null;\n\tif (!defaultScope || defaultScope.kind !== \"team_default\") return null;\n\treturn await coordinatorGrantScopeMembershipAction({\n\t\tgroupId: opts.groupId,\n\t\tscopeId,\n\t\tdeviceId: opts.deviceId,\n\t\trole: \"member\",\n\t\tmembershipEpoch: 1,\n\t\tcoordinatorId,\n\t\tremoteUrl: opts.config.syncCoordinatorUrl || null,\n\t\tadminSecret: opts.config.syncCoordinatorAdminSecret || null,\n\t});\n}\n\nfunction removeConfiguredCoordinatorGroup(groupId: string): string[] {\n\tconst targetGroup = groupId.trim();\n\tif (!targetGroup) return [];\n\tconst config = readCodememConfigFile();\n\tconst rawGroups = config.sync_coordinator_groups;\n\tconst groups = Array.isArray(rawGroups)\n\t\t? rawGroups.map((group) => String(group).trim()).filter(Boolean)\n\t\t: typeof rawGroups === \"string\"\n\t\t\t? rawGroups\n\t\t\t\t\t.split(\",\")\n\t\t\t\t\t.map((group) => group.trim())\n\t\t\t\t\t.filter(Boolean)\n\t\t\t: typeof config.sync_coordinator_group === \"string\" && config.sync_coordinator_group.trim()\n\t\t\t\t? [config.sync_coordinator_group.trim()]\n\t\t\t\t: [];\n\tconst nextGroups = groups.filter((group) => group !== targetGroup);\n\tif (nextGroups.length === groups.length) return groups;\n\tconfig.sync_coordinator_groups = nextGroups;\n\tif (nextGroups.length) config.sync_coordinator_group = nextGroups[0];\n\telse delete config.sync_coordinator_group;\n\twriteCodememConfigFile(config);\n\treturn nextGroups;\n}\n\nfunction coordinatorAdminUnavailable(status: ReturnType<typeof coordinatorAdminStatusPayload>): {\n\tbody: Record<string, unknown>;\n\thttpStatus: 400;\n} | null {\n\tif (status.readiness === \"not_configured\") {\n\t\treturn { body: { error: \"coordinator_not_configured\", status }, httpStatus: 400 };\n\t}\n\tif (!status.has_admin_secret) {\n\t\treturn { body: { error: \"coordinator_admin_secret_missing\", status }, httpStatus: 400 };\n\t}\n\treturn null;\n}\n\nasync function parseViewerJsonBody(\n\tc: Context,\n\toptions: { allowEmpty?: boolean } = {},\n): Promise<Record<string, unknown> | null> {\n\tconst raw = await c.req.text();\n\tif (!raw.trim()) return options.allowEmpty ? {} : null;\n\ttry {\n\t\tconst parsed = JSON.parse(raw) 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 optionalViewerString(body: Record<string, unknown>, key: string): string | null {\n\tconst value = body[key];\n\tif (value == null) return null;\n\treturn String(value).trim() || null;\n}\n\nfunction optionalViewerStrictString(body: Record<string, unknown>, key: string): string | null {\n\tconst value = body[key];\n\tif (value == null) return null;\n\tif (typeof value !== \"string\") throw new Error(`${key} must be string`);\n\treturn value.trim() || null;\n}\n\nfunction optionalViewerStringList(body: Record<string, unknown>, key: string): string[] {\n\tconst value = body[key];\n\tif (value == null) return [];\n\tif (!Array.isArray(value)) throw new Error(`${key} must be an array of strings`);\n\treturn [\n\t\t...new Set(\n\t\t\tvalue\n\t\t\t\t.map((item) => {\n\t\t\t\t\tif (typeof item !== \"string\") throw new Error(`${key} must be an array of strings`);\n\t\t\t\t\treturn item.trim();\n\t\t\t\t})\n\t\t\t\t.filter(Boolean),\n\t\t),\n\t];\n}\n\nfunction optionalViewerNumber(body: Record<string, unknown>, key: string): number | null {\n\tconst value = body[key];\n\tif (value == null || value === \"\") return null;\n\tconst number = typeof value === \"number\" ? value : Number(value);\n\treturn Number.isFinite(number) ? Math.trunc(number) : Number.NaN;\n}\n\nfunction optionalViewerInteger(body: Record<string, unknown>, key: string): number | null {\n\tconst value = body[key];\n\tif (value == null || value === \"\") return null;\n\tconst number = typeof value === \"number\" ? value : Number(value);\n\treturn Number.isInteger(number) ? number : Number.NaN;\n}\n\nfunction missingGuardrailConfirmations(\n\twarnings: ProjectScopeGuardrailWarning[],\n\tconfirmedTokens: string[],\n): ProjectScopeGuardrailWarning[] {\n\tconst confirmed = new Set(confirmedTokens);\n\treturn warnings.filter(\n\t\t(warning) =>\n\t\t\twarning.requires_confirmation &&\n\t\t\t(!warning.confirmation_token || !confirmed.has(warning.confirmation_token)),\n\t);\n}\n\nfunction parseViewerProjectMappingInput(body: Record<string, unknown>) {\n\tconst id = optionalViewerInteger(body, \"id\");\n\tconst priority = optionalViewerInteger(body, \"priority\");\n\tif (Number.isNaN(id)) throw new Error(\"id must be an integer\");\n\tif (Number.isNaN(priority)) throw new Error(\"priority must be an integer\");\n\treturn {\n\t\tid,\n\t\tworkspace_identity: optionalViewerStrictString(body, \"workspace_identity\"),\n\t\tproject_pattern: optionalViewerStrictString(body, \"project_pattern\"),\n\t\tscope_id: optionalViewerStrictString(body, \"scope_id\") ?? \"\",\n\t\tpriority,\n\t\tsource: optionalViewerStrictString(body, \"source\") ?? \"user\",\n\t};\n}\n\nfunction coordinatorAdminMutationStatus(message: string): 400 | 404 | 409 | 502 {\n\tif (\n\t\tmessage.includes(\"scope_not_found\") ||\n\t\tmessage.includes(\"membership_not_found\") ||\n\t\tmessage.includes(\"group_not_found\") ||\n\t\tmessage.includes(\"Group not found\") ||\n\t\tmessage.includes(\"Scope not found\") ||\n\t\tmessage.includes(\"device_not_enrolled_for_scope_group\") ||\n\t\tmessage.includes(\"device must be enrolled\")\n\t) {\n\t\treturn 404;\n\t}\n\tif (\n\t\tmessage.includes(\"not active\") ||\n\t\tmessage.includes(\"scope_not_active\") ||\n\t\tmessage.includes(\"group_archived\") ||\n\t\tmessage.includes(\"Group is archived\")\n\t) {\n\t\treturn 409;\n\t}\n\tif (\n\t\tmessage.includes(\"Remote coordinator request failed (5\") ||\n\t\tmessage.includes(\"fetch failed\") ||\n\t\tmessage.includes(\"network\") ||\n\t\tmessage.includes(\"timed out\")\n\t) {\n\t\treturn 502;\n\t}\n\treturn 400;\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\t{ defaultHttpPort: config.syncPort },\n\t\t);\n\t}\n\tif (config.syncHost && config.syncHost !== \"0.0.0.0\") {\n\t\treturn [normalizeAddress(formatHostPort(config.syncHost, config.syncPort))].filter(Boolean);\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) => normalizeAddress(formatHostPort(address, config.syncPort)))\n\t\t.filter(Boolean);\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\nconst SYNC_AUTH_STORE_BUSY_REASON = \"sync_auth_store_busy\";\n\ntype SyncAuthResult = { ok: boolean; reason: string; deviceId: string };\n\nfunction isSqliteBusy(err: unknown): boolean {\n\tif (!err || typeof err !== \"object\") return false;\n\tconst code = \"code\" in err ? String((err as { code?: unknown }).code ?? \"\") : \"\";\n\tconst message = err instanceof Error ? err.message : \"\";\n\treturn code === \"SQLITE_BUSY\" || message.includes(\"database is locked\");\n}\n\nfunction recordSyncAuthNonce(\n\tstore: MemoryStore,\n\tdeviceId: string,\n\tnonce: string,\n\tcreatedAt: string,\n): SyncAuthResult | null {\n\ttry {\n\t\tif (!recordNonce(store.db, deviceId, nonce, createdAt)) {\n\t\t\treturn { ok: false, reason: \"nonce_replay\", deviceId };\n\t\t}\n\t} catch (err) {\n\t\tif (isSqliteBusy(err)) {\n\t\t\treturn { ok: false, reason: SYNC_AUTH_STORE_BUSY_REASON, deviceId };\n\t\t}\n\t\tthrow err;\n\t}\n\n\tconst cutoff = new Date(Date.now() - DEFAULT_TIME_WINDOW_S * 2 * 1000).toISOString();\n\ttry {\n\t\tcleanupNonces(store.db, cutoff);\n\t} catch (err) {\n\t\tif (!isSqliteBusy(err)) throw err;\n\t\t// Nonce cleanup is best-effort. A lock here should not fail a request\n\t\t// after its nonce was already recorded; the next request can prune.\n\t}\n\treturn null;\n}\n\nfunction isSyncAuthStoreBusy(auth: SyncAuthResult): boolean {\n\treturn !auth.ok && auth.reason === SYNC_AUTH_STORE_BUSY_REASON;\n}\n\nfunction syncAuthStoreBusyResponse(c: Context) {\n\tc.header(\"Retry-After\", \"1\");\n\treturn c.json({ error: SYNC_AUTH_STORE_BUSY_REASON }, 503);\n}\n\nfunction authorizeSyncRequest(\n\tstore: MemoryStore,\n\trequest: { method: string; url: string; header(name: string): string | undefined },\n\tbody: Buffer,\n): SyncAuthResult {\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\tconst nonceResult = recordSyncAuthNonce(store, deviceId, nonce, createdAt);\n\tif (nonceResult) return nonceResult;\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<SyncAuthResult> {\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\tconst nonceResult = recordSyncAuthNonce(store, deviceId, nonce, createdAt);\n\tif (nonceResult) return nonceResult;\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 cleanPeerScopeText(value: unknown): string | null {\n\tconst text = String(value ?? \"\").trim();\n\treturn text || null;\n}\n\nfunction peerAuthorizedScopes(store: MemoryStore, peerDeviceId: string): Record<string, unknown>[] {\n\tconst deviceId = peerDeviceId.trim();\n\tif (!deviceId) return [];\n\tconst rows = store.db\n\t\t.prepare(\n\t\t\t`SELECT\n\t\t\t\trs.scope_id,\n\t\t\t\trs.label,\n\t\t\t\trs.kind,\n\t\t\t\trs.authority_type,\n\t\t\t\trs.coordinator_id,\n\t\t\t\trs.group_id,\n\t\t\t\tsm.role,\n\t\t\t\tsm.membership_epoch,\n\t\t\t\tsm.updated_at\n\t\t\t FROM scope_memberships sm\n\t\t\t JOIN replication_scopes rs ON rs.scope_id = sm.scope_id\n\t\t\t WHERE sm.device_id = ?\n\t\t\t AND sm.status = 'active'\n\t\t\t AND rs.status = 'active'\n\t\t\t AND sm.membership_epoch >= rs.membership_epoch\n\t\t\t ORDER BY CASE WHEN rs.authority_type = 'local' THEN 1 ELSE 0 END,\n\t\t\t rs.label COLLATE NOCASE,\n\t\t\t rs.scope_id`,\n\t\t)\n\t\t.all(deviceId) as Array<Record<string, unknown>>;\n\treturn rows.map((row) => ({\n\t\tscope_id: String(row.scope_id ?? \"\"),\n\t\tlabel: String(row.label ?? row.scope_id ?? \"\"),\n\t\tkind: String(row.kind ?? \"user\"),\n\t\tauthority_type: String(row.authority_type ?? \"local\"),\n\t\tcoordinator_id: cleanPeerScopeText(row.coordinator_id),\n\t\tgroup_id: cleanPeerScopeText(row.group_id),\n\t\trole: String(row.role ?? \"member\"),\n\t\tmembership_epoch: Number(row.membership_epoch ?? 0),\n\t\tupdated_at: cleanPeerScopeText(row.updated_at),\n\t}));\n}\n\nfunction ensureLocalActorRecord(store: MemoryStore): void {\n\tconst d = drizzle(store.db, { schema });\n\tconst now = new Date().toISOString();\n\t// Invariant: exactly one row in `actors` has is_local=1, and it is the\n\t// row whose actor_id matches store.actorId. Stale is_local=1 rows can\n\t// appear when a device's actor_id changes (config edit, regenerated\n\t// device keys, DB copied from another machine). Demote any such rows\n\t// before ensuring the canonical local row exists.\n\td.update(schema.actors)\n\t\t.set({ is_local: 0, updated_at: now })\n\t\t.where(and(eq(schema.actors.is_local, 1), ne(schema.actors.actor_id, store.actorId)))\n\t\t.run();\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) {\n\t\t// Row already exists for the canonical local actor id; the demotion\n\t\t// above guarantees it is the only is_local=1 row, but the row itself\n\t\t// may have been previously set to is_local=0 (e.g. via a stale demote\n\t\t// from an even earlier identity). Re-mark it as local idempotently.\n\t\td.update(schema.actors)\n\t\t\t.set({ is_local: 1, updated_at: now })\n\t\t\t.where(eq(schema.actors.actor_id, store.actorId))\n\t\t\t.run();\n\t\treturn;\n\t}\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 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\tconst addressCount = Array.isArray(record.addresses) ? record.addresses.length : 0;\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\taddress_count: addressCount,\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\ninterface AcceptDiscoveredPeerOptions {\n\tpeerDeviceId: string;\n\tfingerprint?: string;\n\t// Optional per-peer scope override. When undefined the group's scope\n\t// template is applied if auto_seed_scope is enabled; otherwise the peer\n\t// is enrolled with no scope filters.\n\t// Per-field: `undefined` = \"inherit from template\", `null` = \"explicit empty\",\n\t// `string[]` = \"use this list\". This avoids silently wiping the template's\n\t// exclude list when the caller only overrides include (or vice versa).\n\tscopeOverride?: {\n\t\tprojects_include?: string[] | null;\n\t\tprojects_exclude?: string[] | null;\n\t};\n\t// When provided and the caller is the admin-groups endpoint, this group\n\t// must be one of the match's coordinator groups. When undefined (legacy\n\t// /api/sync/peers/accept-discovered path) the match must belong to\n\t// exactly one group and that one is used.\n\texpectedGroupId?: string;\n}\n\ntype AcceptDiscoveredPeerNotConfiguredReason =\n\t| \"coordinator_url_missing\"\n\t| \"coordinator_groups_empty\"\n\t| \"sync_disabled\";\n\nfunction detailForNotConfiguredReason(reason: AcceptDiscoveredPeerNotConfiguredReason): string {\n\tswitch (reason) {\n\t\tcase \"coordinator_url_missing\":\n\t\t\treturn \"Configure a coordinator URL before pairing with discovered peers.\";\n\t\tcase \"coordinator_groups_empty\":\n\t\t\treturn \"Join a coordinator team before pairing with discovered peers.\";\n\t\tcase \"sync_disabled\":\n\t\t\treturn \"Enable sync on this device before pairing with discovered peers.\";\n\t}\n}\n\nasync function acceptDiscoveredPeer(\n\tstore: MemoryStore,\n\tinput: AcceptDiscoveredPeerOptions,\n): Promise<\n\t| {\n\t\t\tok: true;\n\t\t\tpeer_device_id: string;\n\t\t\tcreated: boolean;\n\t\t\tupdated: boolean;\n\t\t\tname: string | null;\n\t\t\tgroup_id: string;\n\t }\n\t| {\n\t\t\tok: false;\n\t\t\tstatus: number;\n\t\t\terror: string;\n\t\t\tdetail: string;\n\t\t\treason?: AcceptDiscoveredPeerNotConfiguredReason;\n\t }\n> {\n\tconst config = readCoordinatorSyncConfig();\n\t// Order: address the most foundational gap first so the detail string\n\t// guides the user through setup in the correct sequence.\n\tlet notConfiguredReason: AcceptDiscoveredPeerNotConfiguredReason | null = null;\n\tif (!config.syncCoordinatorUrl) {\n\t\tnotConfiguredReason = \"coordinator_url_missing\";\n\t} else if (config.syncCoordinatorGroups.length === 0) {\n\t\tnotConfiguredReason = \"coordinator_groups_empty\";\n\t} else if (!config.syncEnabled) {\n\t\tnotConfiguredReason = \"sync_disabled\";\n\t}\n\tif (notConfiguredReason) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 400,\n\t\t\terror: \"coordinator_not_configured\",\n\t\t\treason: notConfiguredReason,\n\t\t\tdetail: detailForNotConfiguredReason(notConfiguredReason),\n\t\t};\n\t}\n\tconst discovered = await lookupCoordinatorPeers(store, config);\n\tconst inputFingerprint = String(input.fingerprint ?? \"\").trim();\n\tconst candidates = discovered.filter(\n\t\t(peer) => String(peer.device_id ?? \"\").trim() === input.peerDeviceId,\n\t);\n\tconst matchingCandidates = inputFingerprint\n\t\t? candidates.filter((peer) => String(peer.fingerprint ?? \"\").trim() === inputFingerprint)\n\t\t: candidates;\n\tconst uniqueFingerprints = new Set(\n\t\tmatchingCandidates.map((peer) => String(peer.fingerprint ?? \"\").trim()).filter(Boolean),\n\t);\n\tif (!inputFingerprint && uniqueFingerprints.size > 1) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"ambiguous_discovered_peer\",\n\t\t\tdetail:\n\t\t\t\t\"That discovered device has multiple coordinator fingerprints. Enable diagnostics, refresh sync status, and choose the intended device before trusting it.\",\n\t\t};\n\t}\n\tconst match = matchingCandidates[0];\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 expiresAt = String(match.expires_at ?? \"\").trim();\n\tconst expired = expiresAt ? Date.parse(expiresAt) <= Date.now() : false;\n\tif (match.stale || expired) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"discovered_peer_stale\",\n\t\t\tdetail:\n\t\t\t\t\"This discovered device's coordinator presence is stale. Wait for it to come online and refresh sync status before trusting it.\",\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\tif (!nextFingerprint || fingerprintPublicKey(nextPublicKey) !== nextFingerprint) {\n\t\treturn {\n\t\t\tok: false,\n\t\t\tstatus: 409,\n\t\t\terror: \"discovered_peer_fingerprint_mismatch\",\n\t\t\tdetail:\n\t\t\t\t\"This discovered device's coordinator public key does not match its fingerprint. Refresh sync status or re-enroll the device before trusting it.\",\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\tconst freshGroupIds = Array.isArray(match.fresh_groups)\n\t\t? match.fresh_groups.map((value) => String(value ?? \"\").trim()).filter(Boolean)\n\t\t: [];\n\tlet groupId: string;\n\tif (input.expectedGroupId) {\n\t\tif (!groupIds.includes(input.expectedGroupId)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 409,\n\t\t\t\terror: \"peer_not_in_group\",\n\t\t\t\tdetail:\n\t\t\t\t\t\"This discovered device is not visible through the specified coordinator group. Refresh sync status and try again.\",\n\t\t\t};\n\t\t}\n\t\tif (!freshGroupIds.includes(input.expectedGroupId)) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 409,\n\t\t\t\terror: \"discovered_peer_stale\",\n\t\t\t\tdetail:\n\t\t\t\t\t\"This discovered device's coordinator presence is stale for the specified group. Wait for it to come online and refresh sync status before trusting it.\",\n\t\t\t};\n\t\t}\n\t\tgroupId = input.expectedGroupId;\n\t} else {\n\t\tif (groupIds.length !== 1) {\n\t\t\treturn {\n\t\t\t\tok: false,\n\t\t\t\tstatus: 409,\n\t\t\t\terror: \"ambiguous_coordinator_group\",\n\t\t\t\tdetail:\n\t\t\t\t\tgroupIds.length > 1\n\t\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\t: \"This device is missing coordinator group context. Refresh sync status and try again.\",\n\t\t\t};\n\t\t}\n\t\tgroupId = groupIds[0] as string;\n\t}\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\tdiscovered_via_group_id: schema.syncPeers.discovered_via_group_id,\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(nextAddresses, existingAddresses));\n\tawait createCoordinatorReciprocalApproval(store, config, {\n\t\tgroupId,\n\t\trequestedDeviceId: input.peerDeviceId,\n\t});\n\n\t// Resolve project-scope seed. On first enrollment (no existing row), apply\n\t// the group's scope template if auto_seed_scope is enabled. Per-field\n\t// overrides fall back to the template when undefined, so passing only\n\t// `projects_include` does not silently wipe the template's exclude list.\n\t// Existing peers are not re-scoped — the template is a seed, not a live link.\n\tconst coordinatorUrl = config.syncCoordinatorUrl || null;\n\tlet scopeInclude: string | null | undefined;\n\tlet scopeExclude: string | null | undefined;\n\tif (!existing) {\n\t\tlet templateInclude: string[] | null = null;\n\t\tlet templateExclude: string[] | null = null;\n\t\tif (coordinatorUrl) {\n\t\t\tconst prefs = getCoordinatorGroupPreference(store.db, coordinatorUrl, groupId);\n\t\t\tif (prefs?.auto_seed_scope) {\n\t\t\t\ttemplateInclude = prefs.projects_include ?? null;\n\t\t\t\ttemplateExclude = prefs.projects_exclude ?? null;\n\t\t\t}\n\t\t}\n\t\tconst overrideInclude = input.scopeOverride?.projects_include;\n\t\tconst overrideExclude = input.scopeOverride?.projects_exclude;\n\t\tconst resolvedInclude = overrideInclude === undefined ? templateInclude : overrideInclude;\n\t\tconst resolvedExclude = overrideExclude === undefined ? templateExclude : overrideExclude;\n\t\tscopeInclude = resolvedInclude ? JSON.stringify(resolvedInclude) : null;\n\t\tscopeExclude = resolvedExclude ? JSON.stringify(resolvedExclude) : null;\n\t}\n\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\tprojects_include_json: scopeInclude ?? null,\n\t\t\t\t\tprojects_exclude_json: scopeExclude ?? null,\n\t\t\t\t\tcreated_at: now,\n\t\t\t\t\tlast_seen_at: now,\n\t\t\t\t\tdiscovered_via_coordinator_id: coordinatorUrl,\n\t\t\t\t\tdiscovered_via_group_id: groupId,\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\tgroup_id: groupId,\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\t// Backfill group-discovery attribution on existing rows if we know\n\t\t\t\t// it now and it wasn't stamped before. Don't overwrite a non-null\n\t\t\t\t// group reference — that would silently move the peer between\n\t\t\t\t// teams and invalidate any template-seeded scope.\n\t\t\t\t...((existing as { discovered_via_group_id?: string | null }).discovered_via_group_id\n\t\t\t\t\t? {}\n\t\t\t\t\t: { discovered_via_group_id: groupId, discovered_via_coordinator_id: coordinatorUrl }),\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\tgroup_id: groupId,\n\t\t};\n\t})();\n\treturn result;\n}\n\nfunction filterOpsForPeer(\n\tstore: MemoryStore,\n\tpeerDeviceId: string,\n\tlocalDeviceId: string | null,\n\tops: ReplicationOp[],\n\toptions: { applyScopeFilter?: boolean } = {},\n): { allowed: ReplicationOp[]; skipped: number; skippedDetail: SafeSkippedSyncDetail | null } {\n\tconst [allowed, , skipped] = filterReplicationOpsForSyncWithStatus(store.db, ops, peerDeviceId, {\n\t\tlocalDeviceId,\n\t\tapplyScopeFilter: options.applyScopeFilter,\n\t});\n\treturn {\n\t\tallowed,\n\t\tskipped: skipped?.skipped_count ?? 0,\n\t\tskippedDetail: skipped ? safeSkippedSyncDetail(skipped) : null,\n\t};\n}\n\n// ---------------------------------------------------------------------------\n// Peer row mapping — deduplicated helper (fix #4)\n// ---------------------------------------------------------------------------\n\nfunction claimedLocalActorScopeStatus(\n\tstore: MemoryStore,\n\trow: Record<string, unknown>,\n): Record<string, unknown> | null {\n\tif (!row.claimed_local_actor) return null;\n\tconst peerDeviceId = String(row.peer_device_id ?? \"\").trim();\n\tconst actorId = String(row.actor_id ?? store.actorId).trim() || store.actorId;\n\tconst grant = personalScopeGrantStatusForPeer(store.db, { peerDeviceId, actorId });\n\treturn {\n\t\tscope_id: grant.scope_id,\n\t\tauthorized: grant.authorized,\n\t\tstate: grant.state,\n\t\taction_required: !grant.authorized,\n\t};\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\trecentOpsByPeer?: Map<string, { in: number; out: number }>,\n\tscopeRejectionsByPeer?: Map<string, InboundScopeRejectionPeerSummary>,\n\tlocalDeviceId?: string | null,\n): Record<string, unknown> {\n\tconst peerId = String(row.peer_device_id ?? \"\");\n\tconst recentOps = recentOpsByPeer?.get(peerId) ?? { in: 0, out: 0 };\n\tconst scopeRejections = scopeRejectionsByPeer?.get(peerId);\n\tconst addresses = safeJsonList(row.addresses_json as string | null);\n\tconst perScopeSync = listPerPeerScopeSyncState(store.db, {\n\t\tlocalDeviceId: localDeviceId ?? null,\n\t\tpeerDeviceId: peerId,\n\t});\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 ? addresses : [],\n\t\taddress_count: addresses.length,\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\tclaimed_local_actor_scope: claimedLocalActorScopeStatus(store, row),\n\t\tactor_id: row.actor_id ?? null,\n\t\tactor_display_name: row.actor_display_name ?? null,\n\t\tauthorized_scopes: peerAuthorizedScopes(store, peerId),\n\t\t// Per-Space sync state intersecting local + peer membership and joining\n\t\t// per-scope replication cursor data. Use this surface to render\n\t\t// per-Space progress in CLI/UI without exposing the legacy `status=ok`\n\t\t// shorthand that hid scoped sync gaps in 0.32.x.\n\t\tper_scope_sync: perScopeSync,\n\t\tproject_scope: {\n\t\t\t...currentProjectScope(row, readPeerProjectFilters(store, String(row.peer_device_id ?? \"\"))),\n\t\t},\n\t\trecent_ops: { in: recentOps.in, out: recentOps.out },\n\t\tscope_rejections: {\n\t\t\ttotal: scopeRejections?.total ?? 0,\n\t\t\tby_reason: scopeRejections?.by_reason ?? {},\n\t\t\tlast_at: scopeRejections?.last_at ?? null,\n\t\t},\n\t\tdiscovered_via_coordinator_id:\n\t\t\ttypeof row.discovered_via_coordinator_id === \"string\"\n\t\t\t\t? row.discovered_via_coordinator_id\n\t\t\t\t: null,\n\t\tdiscovered_via_group_id:\n\t\t\ttypeof row.discovered_via_group_id === \"string\" ? row.discovered_via_group_id : null,\n\t};\n}\n\nfunction redactSyncAttemptError(error: unknown): string | null {\n\tconst text = String(error ?? \"\").trim();\n\tif (!text) return null;\n\treturn \"sync attempt failed; enable diagnostics for details\";\n}\n\nfunction mapSyncAttemptRow(\n\trow: Record<string, unknown>,\n\tshowDiag: boolean,\n\taddresses?: string[],\n): Record<string, unknown> {\n\tconst redactedError = redactSyncAttemptError(row.error);\n\treturn {\n\t\t...row,\n\t\terror: showDiag ? row.error : redactedError,\n\t\terror_redacted: !showDiag && redactedError != null,\n\t\tstatus: attemptStatus(row),\n\t\taddress: showDiag && addresses?.length ? addresses[0] : null,\n\t};\n}\n\nconst SYNC_SCOPE_REJECTION_WINDOW_SECONDS = 24 * 60 * 60;\n\nfunction recentScopeRejectionsByPeer(\n\tstore: MemoryStore,\n): Map<string, InboundScopeRejectionPeerSummary> {\n\tconst cutoff = new Date(Date.now() - SYNC_SCOPE_REJECTION_WINDOW_SECONDS * 1000).toISOString();\n\tconst summaries = summarizeInboundScopeRejections(store.db, { sinceIso: cutoff });\n\tconst map = new Map<string, InboundScopeRejectionPeerSummary>();\n\tfor (const summary of summaries) {\n\t\tconst id = String(summary.peer_device_id ?? \"\").trim();\n\t\tif (!id) continue;\n\t\tmap.set(id, summary);\n\t}\n\treturn map;\n}\n\nfunction legacySharedReviewSummary(store: MemoryStore): Record<string, unknown> {\n\tconst rows = legacySharedReviewRows(store);\n\tconst memoryCount = rows.length;\n\tconst lastUpdatedAt = rows.reduce<string | null>(\n\t\t(current, row) =>\n\t\t\trow.updated_at && (!current || row.updated_at > current) ? row.updated_at : current,\n\t\tnull,\n\t);\n\tconst ownedBySelf = store.buildOwnershipPredicate();\n\tconst candidatesByIdentity = new Map(\n\t\tlistProjectScopeCandidates(store.db, { limit: null }).map((candidate) => [\n\t\t\tcandidate.workspace_identity,\n\t\t\tcandidate,\n\t\t]),\n\t);\n\tconst groupsByIdentity = new Map<\n\t\tstring,\n\t\t{\n\t\t\tworkspace_identity: string;\n\t\t\tidentity_source: string;\n\t\t\tdisplay_project: string;\n\t\t\tmemory_count: number;\n\t\t\treassignable_memory_count: number;\n\t\t\tpeer_owned_memory_count: number;\n\t\t\tlast_updated_at: string | null;\n\t\t\tsuggested_scope_id: string | null;\n\t\t\tsuggestion_reason: string | null;\n\t\t}\n\t>();\n\tfor (const row of rows) {\n\t\tconst identity = canonicalWorkspaceIdentity({\n\t\t\tcwd: row.cwd,\n\t\t\tgitBranch: row.git_branch,\n\t\t\tgitRemote: row.git_remote,\n\t\t\tproject: row.project,\n\t\t\tworkspaceId: row.workspace_id,\n\t\t});\n\t\tconst candidate = candidatesByIdentity.get(identity.value);\n\t\tconst resolvedScope = candidate?.resolved_scope_id ?? null;\n\t\tconst suggestedScope =\n\t\t\tresolvedScope &&\n\t\t\tresolvedScope !== LOCAL_DEFAULT_SCOPE_ID &&\n\t\t\tresolvedScope !== LEGACY_SHARED_REVIEW_SCOPE_ID\n\t\t\t\t? resolvedScope\n\t\t\t\t: candidate?.suggested_scope_id;\n\t\tconst existing = groupsByIdentity.get(identity.value);\n\t\tconst isOwnedBySelf = ownedBySelf(row as unknown as Record<string, unknown>);\n\t\tconst rowUpdatedAt = row.updated_at ?? null;\n\t\tif (existing) {\n\t\t\texisting.memory_count += 1;\n\t\t\tif (isOwnedBySelf) existing.reassignable_memory_count += 1;\n\t\t\telse existing.peer_owned_memory_count += 1;\n\t\t\tif (rowUpdatedAt && (!existing.last_updated_at || rowUpdatedAt > existing.last_updated_at)) {\n\t\t\t\texisting.last_updated_at = rowUpdatedAt;\n\t\t\t}\n\t\t\tcontinue;\n\t\t}\n\t\tgroupsByIdentity.set(identity.value, {\n\t\t\tworkspace_identity: identity.value,\n\t\t\tidentity_source: identity.source,\n\t\t\tdisplay_project: identity.displayProject ?? row.project ?? row.cwd ?? identity.value,\n\t\t\tmemory_count: 1,\n\t\t\treassignable_memory_count: isOwnedBySelf ? 1 : 0,\n\t\t\tpeer_owned_memory_count: isOwnedBySelf ? 0 : 1,\n\t\t\tlast_updated_at: rowUpdatedAt,\n\t\t\tsuggested_scope_id: suggestedScope ?? null,\n\t\t\tsuggestion_reason: suggestedScope\n\t\t\t\t? (candidate?.suggestion_reason ??\n\t\t\t\t\t\"Existing project mapping can be reviewed as a destination, but legacy data is not promoted automatically.\")\n\t\t\t\t: null,\n\t\t});\n\t}\n\tconst totalGroupCount = groupsByIdentity.size;\n\tconst groups = [...groupsByIdentity.values()].sort(\n\t\t(left, right) =>\n\t\t\tright.memory_count - left.memory_count ||\n\t\t\t(right.last_updated_at ?? \"\").localeCompare(left.last_updated_at ?? \"\") ||\n\t\t\tleft.workspace_identity.localeCompare(right.workspace_identity),\n\t);\n\tconst targetScopes = listSharingDomainSettingsScopes(store.db)\n\t\t.filter(\n\t\t\t(scope) =>\n\t\t\t\tscope.scope_id !== LOCAL_DEFAULT_SCOPE_ID &&\n\t\t\t\tscope.scope_id !== LEGACY_SHARED_REVIEW_SCOPE_ID,\n\t\t)\n\t\t.map((scope) => ({\n\t\t\tauthority_type: scope.authority_type,\n\t\t\tlabel: scope.label || scope.scope_id,\n\t\t\tscope_id: scope.scope_id,\n\t\t}));\n\treturn {\n\t\tscope_id: LEGACY_SHARED_REVIEW_SCOPE_ID,\n\t\tmemory_count: memoryCount,\n\t\thas_data: memoryCount > 0,\n\t\tlast_updated_at: lastUpdatedAt,\n\t\tgroups,\n\t\ttotal_group_count: totalGroupCount,\n\t\ttarget_scopes: targetScopes,\n\t};\n}\n\ninterface LegacySharedReviewReassignmentMemoryRow {\n\tid: number;\n\trev: number | null;\n\tactive: number | null;\n\tdeleted_at: string | null;\n\tupdated_at: string | null;\n\tscope_id: string | null;\n\tproject: string | null;\n\tcwd: string | null;\n\tgit_remote: string | null;\n\tgit_branch: string | null;\n\tworkspace_id: string | null;\n\tactor_id: string | null;\n\torigin_device_id: string | null;\n\tmetadata_json: string | null;\n}\n\nfunction legacySharedReviewRows(store: MemoryStore): LegacySharedReviewReassignmentMemoryRow[] {\n\treturn store.db\n\t\t.prepare(\n\t\t\t`SELECT m.id,\n\t\t\t m.rev,\n\t\t\t m.active,\n\t\t\t m.deleted_at,\n\t\t\t m.updated_at,\n\t\t\t m.scope_id,\n\t\t\t s.project,\n\t\t\t s.cwd,\n\t\t\t s.git_remote,\n\t\t\t s.git_branch,\n\t\t\t m.workspace_id,\n\t\t\t m.actor_id,\n\t\t\t m.origin_device_id,\n\t\t\t m.metadata_json\n\t\t\t FROM memory_items m\n\t\t\t LEFT JOIN sessions s ON s.id = m.session_id\n\t\t\t WHERE m.scope_id = ?\n\t\t\t AND m.active = 1\n\t\t\t AND m.deleted_at IS NULL`,\n\t\t)\n\t\t.all(LEGACY_SHARED_REVIEW_SCOPE_ID) as LegacySharedReviewReassignmentMemoryRow[];\n}\n\nfunction legacySharedReviewConfirmationToken(input: {\n\trows: LegacySharedReviewReassignmentMemoryRow[];\n\tscopeId: string;\n\tstore: MemoryStore;\n\tworkspaceIdentity: string;\n}): string {\n\tconst ownedBySelf = input.store.buildOwnershipPredicate();\n\tconst payload = input.rows\n\t\t.map((row) => {\n\t\t\tconst ownership = ownedBySelf(row as unknown as Record<string, unknown>) ? \"local\" : \"peer\";\n\t\t\treturn `${row.id}:${row.rev ?? 0}:${row.scope_id ?? \"\"}:${ownership}`;\n\t\t})\n\t\t.sort()\n\t\t.join(\",\");\n\treturn Buffer.from(`${input.workspaceIdentity}|${input.scopeId}|${payload}`, \"utf8\").toString(\n\t\t\"base64url\",\n\t);\n}\n\ninterface LegacySharedReviewReassignmentPreview {\n\tconfirmation_token: string;\n\tworkspace_identity: string;\n\tscope_id: string;\n\ttarget_scope_label: string;\n\tmemory_count: number;\n\treassignable_memory_count: number;\n\tskipped_memory_count: number;\n\taffected_peer_device_count: number;\n\taffected_peer_device_ids: string[];\n\twarning: string;\n}\n\ninterface ProjectInventoryMemoryRow {\n\tid: number;\n\trev: number | null;\n\tproject: string | null;\n\tcwd: string | null;\n\tgit_remote: string | null;\n\tgit_branch: string | null;\n\tworkspace_id: string | null;\n\tactor_id: string | null;\n\torigin_device_id: string | null;\n\tmetadata_json: string | null;\n}\n\nfunction projectInventoryRowsForWorkspace(\n\tstore: MemoryStore,\n\tworkspaceIdentity: string,\n): ProjectInventoryMemoryRow[] {\n\tconst rows = store.db\n\t\t.prepare(\n\t\t\t`SELECT m.id,\n\t\t\t m.rev,\n\t\t\t s.project,\n\t\t\t s.cwd,\n\t\t\t s.git_remote,\n\t\t\t s.git_branch,\n\t\t\t m.workspace_id,\n\t\t\t m.actor_id,\n\t\t\t m.origin_device_id,\n\t\t\t m.metadata_json\n\t\t\t FROM memory_items m\n\t\t\t LEFT JOIN sessions s ON s.id = m.session_id\n\t\t\t WHERE m.active = 1\n\t\t\t AND m.deleted_at IS NULL`,\n\t\t)\n\t\t.all() as ProjectInventoryMemoryRow[];\n\treturn rows.filter((row) => {\n\t\tconst identity = canonicalWorkspaceIdentity({\n\t\t\tcwd: row.cwd,\n\t\t\tgitBranch: row.git_branch,\n\t\t\tgitRemote: row.git_remote,\n\t\t\tproject: row.project,\n\t\t\tworkspaceId: row.workspace_id,\n\t\t});\n\t\treturn identity.value === workspaceIdentity;\n\t});\n}\n\nfunction projectForgetConfirmationToken(\n\tstore: MemoryStore,\n\trows: ProjectInventoryMemoryRow[],\n): string {\n\tconst ownedBySelf = store.buildOwnershipPredicate();\n\tconst payload = rows\n\t\t.map((row) => {\n\t\t\tconst ownership = ownedBySelf(row as unknown as Record<string, unknown>) ? \"local\" : \"peer\";\n\t\t\treturn `${row.id}:${row.rev ?? 0}:${ownership}`;\n\t\t})\n\t\t.sort()\n\t\t.join(\",\");\n\treturn Buffer.from(payload, \"utf8\").toString(\"base64url\");\n}\n\nfunction forgetProjectInventoryLocalMemories(\n\tstore: MemoryStore,\n\tinput: { confirmationToken?: string | null; confirmed: boolean; workspaceIdentity: string },\n): Record<string, unknown> {\n\tif (!input.workspaceIdentity.trim()) {\n\t\tthrow new Error(\"workspace_identity must be a non-empty string\");\n\t}\n\tconst rows = projectInventoryRowsForWorkspace(store, input.workspaceIdentity);\n\tif (rows.length === 0) throw new Error(\"project identity not found\");\n\tconst ownedBySelf = store.buildOwnershipPredicate();\n\tconst localRows = rows.filter((row) => ownedBySelf(row as unknown as Record<string, unknown>));\n\tconst confirmationToken = projectForgetConfirmationToken(store, rows);\n\tconst preview = {\n\t\tconfirmation_token: confirmationToken,\n\t\tlocal_owned_memory_count: localRows.length,\n\t\tpeer_owned_memory_count: rows.length - localRows.length,\n\t\tworkspace_identity: input.workspaceIdentity,\n\t};\n\tif (!input.confirmed) {\n\t\treturn { confirmed: false, ...preview };\n\t}\n\tif (input.confirmationToken !== confirmationToken) {\n\t\tthrow new Error(\"project memories changed before cleanup; refresh and try again\");\n\t}\n\tstore.db.transaction(() => {\n\t\tfor (const row of localRows) store.forget(row.id);\n\t})();\n\treturn { confirmed: true, forgotten_memory_count: localRows.length, ...preview };\n}\n\nfunction assertLocalDeviceScopeMembership(store: MemoryStore, scopeId: string): void {\n\tif (scopeId === LOCAL_DEFAULT_SCOPE_ID) return;\n\tconst row = store.db\n\t\t.prepare(\n\t\t\t`SELECT 1\n\t\t\t FROM scope_memberships sm\n\t\t\t JOIN replication_scopes rs ON rs.scope_id = sm.scope_id\n\t\t\t WHERE sm.scope_id = ?\n\t\t\t AND sm.device_id = ?\n\t\t\t AND sm.status = 'active'\n\t\t\t AND rs.status = 'active'\n\t\t\t AND sm.membership_epoch >= rs.membership_epoch\n\t\t\t LIMIT 1`,\n\t\t)\n\t\t.get(scopeId, store.deviceId);\n\tif (!row) throw new Error(`local device is not a member of Sharing domain ${scopeId}`);\n}\n\nfunction legacySharedReviewRowsForWorkspace(\n\tstore: MemoryStore,\n\tworkspaceIdentity: string,\n): LegacySharedReviewReassignmentMemoryRow[] {\n\treturn legacySharedReviewRows(store).filter((row) => {\n\t\tconst identity = canonicalWorkspaceIdentity({\n\t\t\tcwd: row.cwd,\n\t\t\tgitBranch: row.git_branch,\n\t\t\tgitRemote: row.git_remote,\n\t\t\tproject: row.project,\n\t\t\tworkspaceId: row.workspace_id,\n\t\t});\n\t\treturn identity.value === workspaceIdentity;\n\t});\n}\n\nfunction reassignableLegacySharedReviewRows(\n\tstore: MemoryStore,\n\trows: LegacySharedReviewReassignmentMemoryRow[],\n): LegacySharedReviewReassignmentMemoryRow[] {\n\tconst reassignableRows = rows.filter((row) =>\n\t\tstore.memoryOwnedBySelf(row as unknown as Record<string, unknown>),\n\t);\n\tif (reassignableRows.length === 0) {\n\t\tthrow new Error(\n\t\t\t\"This legacy review group contains only peer-owned memories; this device cannot reassign them to a Sharing domain.\",\n\t\t);\n\t}\n\tconst currentRows = store.db\n\t\t.prepare(\n\t\t\t`SELECT id, scope_id, active, deleted_at\n\t\t\t FROM memory_items\n\t\t\t WHERE id IN (${reassignableRows.map(() => \"?\").join(\",\")})`,\n\t\t)\n\t\t.all(...reassignableRows.map((row) => row.id)) as Array<{\n\t\tactive: number | null;\n\t\tdeleted_at: string | null;\n\t\tid: number;\n\t\tscope_id: string | null;\n\t}>;\n\tconst currentById = new Map(currentRows.map((row) => [Number(row.id), row]));\n\tfor (const row of reassignableRows) {\n\t\tconst current = currentById.get(row.id);\n\t\tif (\n\t\t\tcurrent?.scope_id !== LEGACY_SHARED_REVIEW_SCOPE_ID ||\n\t\t\tcurrent.active !== 1 ||\n\t\t\tcurrent.deleted_at\n\t\t) {\n\t\t\tthrow new Error(\n\t\t\t\t\"legacy shared review group changed before reassignment; refresh and try again\",\n\t\t\t);\n\t\t}\n\t}\n\treturn reassignableRows;\n}\n\nfunction legacySharedReviewReassignmentPreview(\n\tstore: MemoryStore,\n\tinput: { scopeId: string; workspaceIdentity: string },\n): LegacySharedReviewReassignmentPreview {\n\tif (!input.workspaceIdentity.trim())\n\t\tthrow new Error(\"workspace_identity must be a non-empty string\");\n\tif (!input.scopeId.trim()) throw new Error(\"scope_id must be a non-empty string\");\n\tif (input.scopeId === LOCAL_DEFAULT_SCOPE_ID) {\n\t\tthrow new Error(\"local-default is not a valid target for legacy shared review reassignment\");\n\t}\n\tif (input.scopeId === LEGACY_SHARED_REVIEW_SCOPE_ID) {\n\t\tthrow new Error(\"legacy-shared-review is a review bucket, not an assignable Sharing domain\");\n\t}\n\tconst targetScope = listSharingDomainSettingsScopes(store.db).find(\n\t\t(scope) => scope.scope_id === input.scopeId,\n\t);\n\tif (!targetScope) throw new Error(`scope_id ${input.scopeId} is not an active Sharing domain`);\n\tassertLocalDeviceScopeMembership(store, input.scopeId);\n\tconst rows = legacySharedReviewRowsForWorkspace(store, input.workspaceIdentity);\n\tif (rows.length === 0) throw new Error(\"legacy shared review group not found\");\n\tconst reassignableRows = reassignableLegacySharedReviewRows(store, rows);\n\tconst peerDeviceIds = [\n\t\t...new Set(\n\t\t\trows\n\t\t\t\t.map((row) => String(row.origin_device_id ?? \"\").trim())\n\t\t\t\t.filter((deviceId) => deviceId && deviceId !== store.deviceId),\n\t\t),\n\t].sort();\n\treturn {\n\t\taffected_peer_device_count: peerDeviceIds.length,\n\t\taffected_peer_device_ids: peerDeviceIds.slice(0, 5),\n\t\tconfirmation_token: legacySharedReviewConfirmationToken({\n\t\t\trows,\n\t\t\tscopeId: input.scopeId,\n\t\t\tstore,\n\t\t\tworkspaceIdentity: input.workspaceIdentity,\n\t\t}),\n\t\tmemory_count: rows.length,\n\t\treassignable_memory_count: reassignableRows.length,\n\t\tscope_id: input.scopeId,\n\t\tskipped_memory_count: rows.length - reassignableRows.length,\n\t\ttarget_scope_label: targetScope.label || targetScope.scope_id,\n\t\twarning:\n\t\t\t\"This changes future sync authorization for reassignable local memories. It does not erase data already copied to peers under legacy-shared-review.\",\n\t\tworkspace_identity: input.workspaceIdentity,\n\t};\n}\n\nfunction reassignLegacySharedReviewGroup(\n\tstore: MemoryStore,\n\tinput: { confirmationToken?: string | null; scopeId: string; workspaceIdentity: string },\n): Record<string, unknown> {\n\tconst preview = legacySharedReviewReassignmentPreview(store, input);\n\tif (input.confirmationToken !== preview.confirmation_token) {\n\t\tthrow new Error(\n\t\t\t\"legacy shared review group changed before reassignment; refresh and try again\",\n\t\t);\n\t}\n\tconst rows = reassignableLegacySharedReviewRows(\n\t\tstore,\n\t\tlegacySharedReviewRowsForWorkspace(store, input.workspaceIdentity),\n\t);\n\tstore.db.transaction(() => {\n\t\tfor (const row of rows) store.reassignMemoryScope(row.id, input.scopeId);\n\t})();\n\treturn {\n\t\tok: true,\n\t\t...preview,\n\t\treassigned_memory_count: rows.length,\n\t\tlegacy_shared_review: legacySharedReviewSummary(store),\n\t};\n}\n\n// Aggregate ops_in / ops_out across recent successful sync_attempts per peer.\n// Window: last 24 hours. Feeds the per-peer direction glyph on the Sync tab\n// (↕ bidirectional, ↑ publishing, ↓ subscribed) off real traffic instead of\n// an invented peer-role field.\nconst SYNC_DIRECTION_WINDOW_SECONDS = 24 * 60 * 60;\n\nfunction recentPeerOps(store: MemoryStore): Map<string, { in: number; out: number }> {\n\tconst cutoff = new Date(Date.now() - SYNC_DIRECTION_WINDOW_SECONDS * 1000).toISOString();\n\tconst rows = store.db\n\t\t.prepare(\n\t\t\t`SELECT peer_device_id,\n\t\t\t COALESCE(SUM(ops_in), 0) AS ops_in,\n\t\t\t COALESCE(SUM(ops_out), 0) AS ops_out\n\t\t\t FROM sync_attempts\n\t\t\t WHERE ok = 1 AND finished_at IS NOT NULL AND finished_at >= ?\n\t\t\t GROUP BY peer_device_id`,\n\t\t)\n\t\t.all(cutoff) as Array<{\n\t\tpeer_device_id: string | null;\n\t\tops_in: number | null;\n\t\tops_out: number | null;\n\t}>;\n\tconst map = new Map<string, { in: number; out: number }>();\n\tfor (const row of rows) {\n\t\tconst id = String(row.peer_device_id ?? \"\").trim();\n\t\tif (!id) continue;\n\t\tmap.set(id, { in: Number(row.ops_in ?? 0), out: Number(row.ops_out ?? 0) });\n\t}\n\treturn map;\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\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, p.discovered_via_coordinator_id, p.discovered_via_group_id,\n\t 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 * Compute the negotiated sync capability for a request by combining the\n * server's local capability with the value the caller advertised in the\n * `X-Codemem-Sync-Capability` header. Routes use this to decide whether to\n * honor scoped-sync wire features such as explicit `scope_id` parameters\n * and `/v1/status` `authorized_scopes` enumeration.\n *\n * Unsigned headers are fine here: the server is computing what it is\n * willing to do, not granting access. Per-scope authorization is enforced\n * separately via the membership cache when a scope_id is actually used.\n */\nfunction negotiatedSyncCapability(c: Context) {\n\tconst header = c.req.header(SYNC_CAPABILITY_HEADER) ?? null;\n\treturn negotiateSyncCapability(LOCAL_SYNC_CAPABILITY, normalizeSyncCapability(header));\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\tif (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\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 (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\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\tconst grantPresent = Boolean((c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim());\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sync] bootstrap grant auth failed: reason=${auth.reason} grant_present=${grantPresent} 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, true), 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\tconst negotiated = negotiatedSyncCapability(c);\n\t\t\t\tconst authorizedScopes = isScopedSyncCapability(negotiated)\n\t\t\t\t\t? listAuthorizedScopesForPeer(store.db, {\n\t\t\t\t\t\t\tlocalDeviceId: deviceId,\n\t\t\t\t\t\t\tpeerDeviceId: auth.deviceId,\n\t\t\t\t\t\t})\n\t\t\t\t\t: null;\n\t\t\t\tconst response: Record<string, unknown> = {\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: addSyncScopeToBoundary(syncReset, null),\n\t\t\t\t\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\t\t};\n\t\t\t\tif (authorizedScopes !== null) {\n\t\t\t\t\tresponse.authorized_scopes = authorizedScopes;\n\t\t\t\t}\n\t\t\t\treturn c.json(response);\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 (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\n\t\tif (!auth.ok)\n\t\t\treturn (\n\t\t\t\trateLimitedResponse(c, c.req.path, false) ??\n\t\t\t\tc.json(unauthorizedPayload(auth.reason, true), 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 rawScopeId = c.req.query(SYNC_SCOPE_QUERY_PARAM);\n\t\t\tconst negotiated = negotiatedSyncCapability(c);\n\t\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\tconst scopeRequest = parseSyncScopeRequest(rawScopeId, rawScopeId !== undefined, {\n\t\t\t\tdb: store.db,\n\t\t\t\tlocalDeviceId,\n\t\t\t\tnegotiatedCapability: negotiated,\n\t\t\t\tpeerDeviceId,\n\t\t\t});\n\t\t\tif (!scopeRequest.ok) {\n\t\t\t\treturn c.json(\n\t\t\t\t\tsyncScopeResetRequiredPayload(\n\t\t\t\t\t\tgetSyncResetState(store.db),\n\t\t\t\t\t\tscopeRequest.reason,\n\t\t\t\t\t\tLOCAL_SYNC_CAPABILITY,\n\t\t\t\t\t\tnull,\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 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 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\tscopeId: scopeRequest.mode === \"scoped\" ? scopeRequest.scope_id : undefined,\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\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\t\t\t\t...addSyncScopeToBoundary(result.reset, scopeRequest.scope_id),\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, localDeviceId, ops);\n\t\t\treturn c.json({\n\t\t\t\treset_required: false,\n\t\t\t\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\t\tscope_id: scopeRequest.scope_id,\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\tskipped_detail: filtered.skippedDetail,\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\tif (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\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 (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\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\tconst grantPresent = Boolean((c.req.header(\"X-Codemem-Bootstrap-Grant\") ?? \"\").trim());\n\t\t\t\t\tconsole.warn(\n\t\t\t\t\t\t`[sync] bootstrap grant auth failed: reason=${auth.reason} grant_present=${grantPresent} 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, true), 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 rawScopeId = c.req.query(SYNC_SCOPE_QUERY_PARAM);\n\t\t\t\tconst negotiated = negotiatedSyncCapability(c);\n\t\t\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\t\tconst scopeRequest = parseSyncScopeRequest(rawScopeId, rawScopeId !== undefined, {\n\t\t\t\t\tdb: store.db,\n\t\t\t\t\tlocalDeviceId,\n\t\t\t\t\tnegotiatedCapability: negotiated,\n\t\t\t\t\tpeerDeviceId: auth.deviceId,\n\t\t\t\t});\n\t\t\t\tif (!scopeRequest.ok) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\tsyncScopeResetRequiredPayload(\n\t\t\t\t\t\t\tgetSyncResetState(store.db),\n\t\t\t\t\t\t\tscopeRequest.reason,\n\t\t\t\t\t\t\tLOCAL_SYNC_CAPABILITY,\n\t\t\t\t\t\t\tnull,\n\t\t\t\t\t\t),\n\t\t\t\t\t\t409,\n\t\t\t\t\t);\n\t\t\t\t}\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\tscopeId: scopeRequest.mode === \"scoped\" ? scopeRequest.scope_id : undefined,\n\t\t\t\t});\n\n\t\t\t\treturn c.json({\n\t\t\t\t\tscope_id: scopeRequest.scope_id,\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\tsync_capability: LOCAL_SYNC_CAPABILITY,\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 (isSyncAuthStoreBusy(auth)) return syncAuthStoreBusyResponse(c);\n\t\tif (!auth.ok)\n\t\t\treturn (\n\t\t\t\trateLimitedResponse(c, c.req.path, false) ??\n\t\t\t\tc.json(unauthorizedPayload(auth.reason, true), 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\tconst negotiated = negotiateSyncCapability(\n\t\t\tLOCAL_SYNC_CAPABILITY,\n\t\t\tnormalizeSyncCapability(body.sync_capability),\n\t\t);\n\t\tconst [localDeviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\tconst scopeRequest = parseSyncScopeRequest(body.scope_id, Object.hasOwn(body, \"scope_id\"), {\n\t\t\tdb: store.db,\n\t\t\tlocalDeviceId,\n\t\t\tnegotiatedCapability: negotiated,\n\t\t\tpeerDeviceId,\n\t\t});\n\t\tif (!scopeRequest.ok) {\n\t\t\treturn c.json(\n\t\t\t\tsyncScopeResetRequiredPayload(\n\t\t\t\t\tgetSyncResetState(store.db),\n\t\t\t\t\tscopeRequest.reason,\n\t\t\t\t\tLOCAL_SYNC_CAPABILITY,\n\t\t\t\t\tnull,\n\t\t\t\t),\n\t\t\t\t409,\n\t\t\t);\n\t\t}\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\t// Inbound POSTs still use legacy visibility/project filters, but must not run\n\t\t// the outbound scope gate. Unsupported peers deliberately bypass strict inbound\n\t\t// scope rejection during rollout, so outbound filtering would silently drop data.\n\t\tconst filtered = filterOpsForPeer(store, peerDeviceId, localDeviceId, normalizedOps, {\n\t\t\tapplyScopeFilter: false,\n\t\t});\n\t\t// Scope validation runs against the full signed batch so bad scoped ops cannot\n\t\t// evade fail-closed rejection by also tripping peer project filters.\n\t\tconst rejected = rejectInboundScopeFailures(store.db, normalizedOps, localDeviceId, {\n\t\t\tenabled: negotiated !== \"unsupported\",\n\t\t\tpeerDeviceId,\n\t\t});\n\t\tif (rejected) {\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: \"scope_rejected\",\n\t\t\t\t\treason: rejected.rejections[0]?.reason ?? \"scope_mismatch\",\n\t\t\t\t\trejections: rejected.rejections,\n\t\t\t\t\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\t\t\tscope_id: scopeRequest.scope_id,\n\t\t\t\t},\n\t\t\t\t403,\n\t\t\t);\n\t\t}\n\n\t\tconst result = applyReplicationOps(store.db, filtered.allowed, localDeviceId, store.scanner);\n\t\tconst skipped = result.skipped + filtered.skipped;\n\t\treturn c.json({\n\t\t\t...result,\n\t\t\tskipped,\n\t\t\tskipped_detail: filtered.skippedDetail,\n\t\t\tsync_capability: LOCAL_SYNC_CAPABILITY,\n\t\t\tscope_id: scopeRequest.scope_id,\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\t// Always take the fast COUNT(DISTINCT) path. The slow\n\t\t\t// per-memory vec0 probe blocks the event loop for seconds on\n\t\t\t// larger DBs, which hangs every concurrent request — not\n\t\t\t// acceptable from a status endpoint. See codemem-00jn.\n\t\t\tconst semanticIndex = traceSync(\"semanticIndex\", () =>\n\t\t\t\tredactSemanticIndexDiagnostics(getSemanticIndexDiagnostics(store.db), showDiag),\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\t// The sync daemon runs inside the viewer-server process itself, so\n\t\t\t// if this request is being served, the daemon is by definition\n\t\t\t// running — the viewer is serving us right now. The prior\n\t\t\t// `portOpen` self-probe occasionally timed out under GC / socket\n\t\t\t// backlog pressure and mis-reported \"stopped · unreachable\" while\n\t\t\t// every other request kept succeeding. Trust the pidfile's\n\t\t\t// existence (a record was written at startup) and skip the loopback\n\t\t\t// probe.\n\t\t\tconst daemonRunning = Boolean(viewerBinding);\n\t\t\tconst daemonDetail = viewerBinding\n\t\t\t\t? `viewer pidfile at ${viewerBinding.host}:${viewerBinding.port}`\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\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\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 recentOpsByPeer = traceSync(\"recentPeerOps\", () => recentPeerOps(store));\n\t\t\tconst scopeRejectionsByPeer = traceSync(\"recentScopeRejectionsByPeer\", () =>\n\t\t\t\trecentScopeRejectionsByPeer(store),\n\t\t\t);\n\t\t\tconst peersItems = peerRows.map((row) => {\n\t\t\t\tconst peer = mapPeerRow(\n\t\t\t\t\tstore,\n\t\t\t\t\trow,\n\t\t\t\t\tshowDiag,\n\t\t\t\t\trecentOpsByPeer,\n\t\t\t\t\tscopeRejectionsByPeer,\n\t\t\t\t\t(deviceRow?.device_id as string | null | undefined) ?? null,\n\t\t\t\t);\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\tlocal_sync_capability: schema.syncAttempts.local_sync_capability,\n\t\t\t\t\t\tpeer_sync_capability: schema.syncAttempts.peer_sync_capability,\n\t\t\t\t\t\tnegotiated_sync_capability: schema.syncAttempts.negotiated_sync_capability,\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 mapSyncAttemptRow(row, showDiag, addrs);\n\t\t\t});\n\t\t\tconst latestAttemptError = String(attemptRows[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 legacyReview = traceSync(\"legacySharedReview\", () => legacySharedReviewSummary(store));\n\t\t\tconst sharingReview = traceSync(\"sharingReview\", () => store.sharingReviewSummary(project));\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\tlegacy_shared_review: legacyReview,\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\tconst recentOpsByPeer = recentPeerOps(store);\n\t\t\tconst scopeRejectionsByPeer = recentScopeRejectionsByPeer(store);\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\tconst deviceRow = d\n\t\t\t\t.select({ device_id: schema.syncDevice.device_id })\n\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t.limit(1)\n\t\t\t\t.get();\n\t\t\tconst localDeviceId = (deviceRow?.device_id as string | null | undefined) ?? null;\n\t\t\t// Use deduplicated mapPeerRow helper (fix #4)\n\t\t\tconst peers = rows.map((row) =>\n\t\t\t\tmapPeerRow(store, row, showDiag, recentOpsByPeer, scopeRejectionsByPeer, localDeviceId),\n\t\t\t);\n\t\t\treturn c.json({ items: peers, redacted: !showDiag });\n\t\t}\n\t});\n\n\t// GET /api/sync/peers/:peer_device_id/scope-rejections\n\t//\n\t// Recent scope-rejection records produced by the inbound fail-closed gate.\n\t// Each row is metadata only — op id, entity ref, scope id, reason code,\n\t// timestamp. The rejection log never stores op payloads, so this endpoint\n\t// can never leak inbound payload contents regardless of diagnostics state.\n\tapp.get(\"/api/sync/peers/:peer_device_id/scope-rejections\", (c) => {\n\t\tconst store = getStore();\n\t\tconst peerDeviceId = String(c.req.param(\"peer_device_id\") || \"\").trim();\n\t\tif (!peerDeviceId) return c.json({ error: \"missing_peer_device_id\" }, 400);\n\t\tconst limit = queryInt(c.req.query(\"limit\"), 100);\n\t\tif (limit <= 0) return c.json({ error: \"invalid_limit\" }, 400);\n\t\tconst sinceMinutesRaw = queryInt(c.req.query(\"sinceMinutes\"), 24 * 60);\n\t\t// Cap at ~10 years so a hostile or fat-fingered query cannot push the\n\t\t// computed timestamp past the Date range and turn toISOString() into\n\t\t// a 500. Anything older than 10 years is effectively \"all rejections\".\n\t\tconst SINCE_MINUTES_MAX = 10 * 365 * 24 * 60;\n\t\tconst sinceMinutes = Math.min(Math.max(sinceMinutesRaw, 0), SINCE_MINUTES_MAX);\n\t\tconst sinceIso =\n\t\t\tsinceMinutes > 0 ? new Date(Date.now() - sinceMinutes * 60_000).toISOString() : undefined;\n\t\tconst records = listInboundScopeRejections(store.db, {\n\t\t\tpeerDeviceId,\n\t\t\tsinceIso,\n\t\t\tlimit,\n\t\t});\n\t\tconst summaries = summarizeInboundScopeRejections(store.db, {\n\t\t\tpeerDeviceId,\n\t\t\tsinceIso,\n\t\t});\n\t\tconst summary = summaries[0] ?? {\n\t\t\tpeer_device_id: peerDeviceId,\n\t\t\ttotal: 0,\n\t\t\tby_reason: {},\n\t\t\tlast_at: null,\n\t\t};\n\t\treturn c.json({\n\t\t\tpeer_device_id: peerDeviceId,\n\t\t\tsummary,\n\t\t\titems: records,\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\tlocal_sync_capability: schema.syncAttempts.local_sync_capability,\n\t\t\t\t\tpeer_sync_capability: schema.syncAttempts.peer_sync_capability,\n\t\t\t\t\tnegotiated_sync_capability: schema.syncAttempts.negotiated_sync_capability,\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\tconst showDiag = queryBool(c.req.query(\"includeDiagnostics\"));\n\t\t\tconst items = rows.map((row) => mapSyncAttemptRow(row, showDiag));\n\t\t\treturn c.json({ items, redacted: !showDiag });\n\t\t}\n\t});\n\n\t// GET /api/sync/pairing — uses ensureDeviceIdentity from core (fix #5 context)\n\t//\n\t// The pairing payload is not redacted by the generic diagnostics toggle:\n\t// it is the actual command the user shares with their own other devices,\n\t// and the UI already hides it inside a \"Show pairing command\" disclosure\n\t// that they explicitly open. Redacting the payload here broke the\n\t// happy-path pairing flow because the UI had nothing to render as the\n\t// command when diagnostics were off.\n\tapp.get(\"/api/sync/pairing\", (c) => {\n\t\tconst store = getStore();\n\t\t{\n\t\t\tconst config = readCoordinatorSyncConfig();\n\t\t\tconst d = drizzle(store.db, { schema });\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\ttry {\n\t\t\t\tconst [id, fp] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\t\tdeviceId = id;\n\t\t\t\tfingerprint = fp;\n\t\t\t\tconst row = d\n\t\t\t\t\t.select({ public_key: schema.syncDevice.public_key })\n\t\t\t\t\t.from(schema.syncDevice)\n\t\t\t\t\t.where(eq(schema.syncDevice.device_id, id))\n\t\t\t\t\t.get();\n\t\t\t\tpublicKey = row?.public_key ?? \"\";\n\t\t\t} catch {\n\t\t\t\treturn c.json({ error: \"device identity unavailable\" }, 500);\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, { scanner: store.scanner });\n\t\t\titems.push({\n\t\t\t\tpeer_device_id: peerId,\n\t\t\t\t...result,\n\t\t\t\tskippedOut: undefined,\n\t\t\t\tskipped_out: safeSkippedSyncDetail(result.skippedOut),\n\t\t\t});\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.get(\"/api/sync/sharing-domains/settings\", (c) => {\n\t\tconst store = getStore();\n\t\tconst limit = Math.max(1, queryInt(c.req.query(\"limit\"), 250));\n\t\treturn c.json({\n\t\t\tscopes: listSharingDomainSettingsScopes(store.db),\n\t\t\tmappings: listProjectScopeSettingsMappings(store.db),\n\t\t\tprojects: listProjectScopeCandidates(store.db, { limit }),\n\t\t\tlocal_default_scope_id: LOCAL_DEFAULT_SCOPE_ID,\n\t\t});\n\t});\n\n\tapp.get(\"/api/sync/projects\", (c) => {\n\t\tconst store = getStore();\n\t\tconst limit = Math.max(1, queryInt(c.req.query(\"limit\"), 50));\n\t\tconst offset = Math.max(0, queryInt(c.req.query(\"offset\"), 0));\n\t\treturn c.json(\n\t\t\tlistProjectScopeInventory(store.db, {\n\t\t\t\tidentitySource: c.req.query(\"identity_source\"),\n\t\t\t\tlimit,\n\t\t\t\toffset,\n\t\t\t\tquery: c.req.query(\"q\"),\n\t\t\t\tscopeId: c.req.query(\"scope_id\"),\n\t\t\t\tstatus: c.req.query(\"status\"),\n\t\t\t}),\n\t\t);\n\t});\n\n\tapp.post(\"/api/sync/projects/reassign-project\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst workspaceIdentity = optionalViewerStrictString(body, \"workspace_identity\") ?? \"\";\n\t\t\tconst project = optionalViewerStrictString(body, \"project\") ?? \"\";\n\t\t\tconst [deviceId] = ensureDeviceIdentity(store.db, { keysDir: syncKeysDir() });\n\t\t\tconst result = reassignProjectScopeInventoryProject(store.db, {\n\t\t\t\tdeviceId,\n\t\t\t\tproject,\n\t\t\t\tworkspaceIdentity,\n\t\t\t});\n\t\t\treturn c.json({ ok: true, ...result });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message }, message.includes(\"not found\") ? 404 : 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/projects/forget\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst workspaceIdentity = optionalViewerStrictString(body, \"workspace_identity\") ?? \"\";\n\t\t\tconst confirmationToken = optionalViewerStrictString(body, \"confirmation_token\");\n\t\t\tconst confirmed = body.confirmed === true;\n\t\t\tconst result = forgetProjectInventoryLocalMemories(store, {\n\t\t\t\tconfirmationToken,\n\t\t\t\tconfirmed,\n\t\t\t\tworkspaceIdentity,\n\t\t\t});\n\t\t\tif (!confirmed) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"project_forget_confirmation_required\",\n\t\t\t\t\t\tpreview: result,\n\t\t\t\t\t},\n\t\t\t\t\t409,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json({ ok: true, ...result });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message }, message.includes(\"not found\") ? 404 : 400);\n\t\t}\n\t});\n\n\tapp.post(\"/api/sync/legacy-shared-review/reassign\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst workspaceIdentity = optionalViewerStrictString(body, \"workspace_identity\") ?? \"\";\n\t\t\tconst scopeId = optionalViewerStrictString(body, \"scope_id\") ?? \"\";\n\t\t\tconst confirmationToken = optionalViewerStrictString(body, \"confirmation_token\");\n\t\t\tconst confirmedOldCopies = body.confirmed_old_copies === true;\n\t\t\tconst preview = legacySharedReviewReassignmentPreview(store, {\n\t\t\t\tscopeId,\n\t\t\t\tworkspaceIdentity,\n\t\t\t});\n\t\t\tif (!confirmedOldCopies) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"legacy_review_confirmation_required\",\n\t\t\t\t\t\tmessage: preview.warning,\n\t\t\t\t\t\tpreview,\n\t\t\t\t\t},\n\t\t\t\t\t409,\n\t\t\t\t);\n\t\t\t}\n\t\t\treturn c.json(\n\t\t\t\treassignLegacySharedReviewGroup(store, {\n\t\t\t\t\tconfirmationToken,\n\t\t\t\t\tscopeId,\n\t\t\t\t\tworkspaceIdentity,\n\t\t\t\t}),\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message }, message.includes(\"not found\") ? 404 : 400);\n\t\t}\n\t});\n\n\tapp.put(\"/api/sync/sharing-domains/project-mappings\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst confirmedGuardrailTokens = optionalViewerStringList(body, \"confirmed_guardrail_tokens\");\n\t\t\tconst mappingInput = parseViewerProjectMappingInput(body);\n\t\t\tconst analysis = analyzeProjectScopeMappingChangeGuardrails(store.db, mappingInput);\n\t\t\tif (analysis.requested_workspace_identity?.startsWith(\"unmapped:\")) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"unmapped_project_local_only\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Unmapped projects need a stable path, git remote, or workspace id before assigning a Sharing domain.\",\n\t\t\t\t\t\tguardrail_warnings: analysis.warnings,\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst missingConfirmations = missingGuardrailConfirmations(\n\t\t\t\tanalysis.warnings,\n\t\t\t\tconfirmedGuardrailTokens,\n\t\t\t);\n\t\t\tif (missingConfirmations.length > 0) {\n\t\t\t\tconst missingCodes = [...new Set(missingConfirmations.map((warning) => warning.code))];\n\t\t\t\tconst missingTokens = [\n\t\t\t\t\t...new Set(missingConfirmations.map((warning) => warning.confirmation_token)),\n\t\t\t\t].filter((token): token is string => typeof token === \"string\" && token.length > 0);\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"guardrail_confirmation_required\",\n\t\t\t\t\t\trequired_guardrails: missingCodes,\n\t\t\t\t\t\trequired_guardrail_tokens: missingTokens,\n\t\t\t\t\t\tguardrail_warnings: analysis.warnings,\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 mapping = upsertProjectScopeSettingsMapping(store.db, {\n\t\t\t\t...mappingInput,\n\t\t\t});\n\t\t\treturn c.json({ ok: true, mapping, guardrail_warnings: analysis.warnings });\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.put(\"/api/sync/sharing-domains/project-mappings/bulk\", async (c) => {\n\t\tconst store = getStore();\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\" }, 400);\n\t\ttry {\n\t\t\tconst rawMappings = body.mappings;\n\t\t\tif (!Array.isArray(rawMappings) || rawMappings.length === 0) {\n\t\t\t\treturn c.json({ error: \"mappings must be a non-empty array\" }, 400);\n\t\t\t}\n\t\t\tconst mappingInputs = rawMappings.map((raw) => {\n\t\t\t\tif (raw == null || typeof raw !== \"object\" || Array.isArray(raw)) {\n\t\t\t\t\tthrow new Error(\"each mapping must be an object\");\n\t\t\t\t}\n\t\t\t\treturn parseViewerProjectMappingInput(raw as Record<string, unknown>);\n\t\t\t});\n\t\t\tconst analyses = mappingInputs.map((mappingInput) =>\n\t\t\t\tanalyzeProjectScopeMappingChangeGuardrails(store.db, mappingInput),\n\t\t\t);\n\t\t\tconst unmapped = analyses.find((analysis) =>\n\t\t\t\tanalysis.requested_workspace_identity?.startsWith(\"unmapped:\"),\n\t\t\t);\n\t\t\tif (unmapped) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"unmapped_project_local_only\",\n\t\t\t\t\t\tmessage:\n\t\t\t\t\t\t\t\"Unmapped projects need a stable path, git remote, or workspace id before assigning a Sharing domain.\",\n\t\t\t\t\t\tguardrail_warnings: unmapped.warnings,\n\t\t\t\t\t},\n\t\t\t\t\t400,\n\t\t\t\t);\n\t\t\t}\n\t\t\tconst missingConfirmations = analyses.flatMap((analysis) =>\n\t\t\t\tmissingGuardrailConfirmations(analysis.warnings, []),\n\t\t\t);\n\t\t\tif (missingConfirmations.length > 0) {\n\t\t\t\tconst missingCodes = [...new Set(missingConfirmations.map((warning) => warning.code))];\n\t\t\t\tconst missingTokens = [\n\t\t\t\t\t...new Set(missingConfirmations.map((warning) => warning.confirmation_token)),\n\t\t\t\t].filter((token): token is string => typeof token === \"string\" && token.length > 0);\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: \"guardrail_confirmation_required\",\n\t\t\t\t\t\trequired_guardrails: missingCodes,\n\t\t\t\t\t\trequired_guardrail_tokens: missingTokens,\n\t\t\t\t\t\tguardrail_warnings: analyses.flatMap((analysis) => analysis.warnings),\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 saveMappings = store.db.transaction(() =>\n\t\t\t\tmappingInputs.map((mappingInput) =>\n\t\t\t\t\tupsertProjectScopeSettingsMapping(store.db, mappingInput),\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\tmappings: saveMappings(),\n\t\t\t\tguardrail_warnings: analyses.flatMap((analysis) => analysis.warnings),\n\t\t\t});\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.delete(\"/api/sync/sharing-domains/project-mappings/:id\", (c) => {\n\t\tconst store = getStore();\n\t\tconst id = Number(c.req.param(\"id\"));\n\t\ttry {\n\t\t\tconst deleted = deleteProjectScopeSettingsMapping(store.db, id);\n\t\t\treturn c.json({ ok: true, deleted });\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/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\ttry {\n\t\t\tconst result = await acceptDiscoveredPeer(store, {\n\t\t\t\tpeerDeviceId,\n\t\t\t\tfingerprint: fingerprint || undefined,\n\t\t\t});\n\t\t\tif (!result.ok) {\n\t\t\t\treturn c.json(\n\t\t\t\t\t{\n\t\t\t\t\t\terror: result.error,\n\t\t\t\t\t\tdetail: result.detail,\n\t\t\t\t\t\t...(result.reason ? { reason: result.reason } : {}),\n\t\t\t\t\t},\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\t// POST /api/sync/invites/import accepts both team invites (coordinator\n\t// invite envelope or codemem:// link) and device-pairing payloads\n\t// (base64 JSON with { device_id, fingerprint, public_key, addresses }).\n\t// The server discriminates by decoding the pasted text — UI callers get\n\t// one textarea for both flows. Response carries `type: \"team_join\"` or\n\t// `type: \"pair\"` so the UI can render the right success message.\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 rawValue = String(body.invite ?? \"\").trim();\n\t\tif (!rawValue) return c.json({ error: \"invite required\" }, 400);\n\n\t\t// Users often paste the whole shell command emitted by the Pairing\n\t\t// diagnostics disclosure (`echo '<b64>' | base64 -d | codemem sync\n\t\t// pair --accept-file -`). Peel the base64 out if we see that shape.\n\t\tconst shellMatch = rawValue.match(\n\t\t\t/echo\\s+['\"]([A-Za-z0-9+/=]+)['\"]\\s*\\|\\s*base64\\s+-d\\s*\\|\\s*codemem/,\n\t\t);\n\t\tconst normalized = shellMatch?.[1]?.trim() || rawValue;\n\n\t\tconst pairingResult = tryParsePairingPayload(normalized);\n\t\tif (pairingResult?.kind === \"invalid-pair\") {\n\t\t\treturn c.json({ error: pairingResult.error }, 400);\n\t\t}\n\t\tif (pairingResult?.kind === \"pair\") {\n\t\t\ttry {\n\t\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\t\tconst existing = d\n\t\t\t\t\t.select({ pinned_fingerprint: schema.syncPeers.pinned_fingerprint })\n\t\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, pairingResult.device_id))\n\t\t\t\t\t.get();\n\t\t\t\tconst existingFingerprint = String(existing?.pinned_fingerprint ?? \"\").trim();\n\t\t\t\tif (existingFingerprint && existingFingerprint !== pairingResult.fingerprint) {\n\t\t\t\t\treturn c.json(\n\t\t\t\t\t\t{\n\t\t\t\t\t\t\terror: \"peer_conflict\",\n\t\t\t\t\t\t\tdetail:\n\t\t\t\t\t\t\t\t\"Pairing payload conflicts with the existing trusted fingerprint for this device. Remove or repair the old peer before accepting this pairing payload.\",\n\t\t\t\t\t\t},\n\t\t\t\t\t\t409,\n\t\t\t\t\t);\n\t\t\t\t}\n\t\t\t\tupdatePeerAddresses(store.db, pairingResult.device_id, pairingResult.addresses, {\n\t\t\t\t\tpinnedFingerprint: pairingResult.fingerprint,\n\t\t\t\t\tpublicKey: pairingResult.public_key,\n\t\t\t\t\treplaceTrust: true,\n\t\t\t\t});\n\t\t\t\treturn c.json({\n\t\t\t\t\tok: true,\n\t\t\t\t\ttype: \"pair\",\n\t\t\t\t\tpeer_device_id: pairingResult.device_id,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\treturn c.json({ error: error instanceof Error ? error.message : String(error) }, 400);\n\t\t\t}\n\t\t}\n\n\t\ttry {\n\t\t\tconst result = await coordinatorImportInviteAction({\n\t\t\t\tinviteValue: rawValue,\n\t\t\t\tdbPath: store.dbPath,\n\t\t\t});\n\t\t\treturn c.json({ ...result, type: \"team_join\" });\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 }, coordinatorAdminMutationStatus(message));\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\ttry {\n\t\t\t\tconst defaultSpace = await ensureDefaultSpaceForTeam({\n\t\t\t\t\tstore: getStore(),\n\t\t\t\t\tconfig,\n\t\t\t\t\tgroupId,\n\t\t\t\t\tdisplayName: displayName || group.display_name || null,\n\t\t\t\t});\n\t\t\t\treturn c.json({ ok: true, group, default_space: defaultSpace, status });\n\t\t\t} catch (setupError) {\n\t\t\t\treturn c.json({\n\t\t\t\t\tok: true,\n\t\t\t\t\tgroup,\n\t\t\t\t\tdefault_space: null,\n\t\t\t\t\tsetup_warning: {\n\t\t\t\t\t\tstep: \"default_space\",\n\t\t\t\t\t\terror: setupError instanceof Error ? setupError.message : String(setupError),\n\t\t\t\t\t},\n\t\t\t\t\tstatus,\n\t\t\t\t});\n\t\t\t}\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\tconst groups = removeConfiguredCoordinatorGroup(groupId);\n\t\t\treturn c.json({\n\t\t\t\tok: true,\n\t\t\t\tgroup,\n\t\t\t\tstatus: coordinatorAdminStatusPayload(),\n\t\t\t\tdisconnected_group_id: groupId,\n\t\t\t\tgroups,\n\t\t\t});\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.get(\"/api/coordinator/admin/groups/:group_id/scopes\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\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 items = await coordinatorListScopesAction({\n\t\t\t\tgroupId,\n\t\t\t\tincludeInactive: queryBool(c.req.query(\"include_inactive\")),\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, 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 }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/scopes\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\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\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\", status }, 400);\n\t\tconst scopeId = optionalViewerString(body, \"scope_id\");\n\t\tconst label = optionalViewerString(body, \"label\");\n\t\tconst membershipEpoch = optionalViewerNumber(body, \"membership_epoch\");\n\t\tif (!scopeId || !label) return c.json({ error: \"scope_id and label required\", status }, 400);\n\t\tif (Number.isNaN(membershipEpoch)) {\n\t\t\treturn c.json({ error: \"membership_epoch must be number\", status }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst scope = await coordinatorCreateScopeAction({\n\t\t\t\tgroupId,\n\t\t\t\tscopeId,\n\t\t\t\tlabel,\n\t\t\t\tkind: optionalViewerString(body, \"kind\"),\n\t\t\t\tauthorityType: optionalViewerString(body, \"authority_type\"),\n\t\t\t\tcoordinatorId: optionalViewerString(body, \"coordinator_id\"),\n\t\t\t\tmanifestIssuerDeviceId: optionalViewerString(body, \"manifest_issuer_device_id\"),\n\t\t\t\tmembershipEpoch,\n\t\t\t\tmanifestHash: optionalViewerString(body, \"manifest_hash\"),\n\t\t\t\tstatus: optionalViewerString(body, \"status\"),\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, scope, group_id: groupId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message, status }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.patch(\"/api/coordinator/admin/groups/:group_id/scopes/:scope_id\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tconst scopeId = String(c.req.param(\"scope_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (!scopeId) return c.json({ error: \"scope_id required\", status }, 400);\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\", status }, 400);\n\t\tconst membershipEpoch = optionalViewerNumber(body, \"membership_epoch\");\n\t\tif (Number.isNaN(membershipEpoch)) {\n\t\t\treturn c.json({ error: \"membership_epoch must be number\", status }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst scope = await coordinatorUpdateScopeAction({\n\t\t\t\tgroupId,\n\t\t\t\tscopeId,\n\t\t\t\tlabel: body.label === undefined ? undefined : optionalViewerString(body, \"label\"),\n\t\t\t\tkind: body.kind === undefined ? undefined : optionalViewerString(body, \"kind\"),\n\t\t\t\tauthorityType:\n\t\t\t\t\tbody.authority_type === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: optionalViewerString(body, \"authority_type\"),\n\t\t\t\tcoordinatorId:\n\t\t\t\t\tbody.coordinator_id === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: optionalViewerString(body, \"coordinator_id\"),\n\t\t\t\tmanifestIssuerDeviceId:\n\t\t\t\t\tbody.manifest_issuer_device_id === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: optionalViewerString(body, \"manifest_issuer_device_id\"),\n\t\t\t\tmembershipEpoch,\n\t\t\t\tmanifestHash:\n\t\t\t\t\tbody.manifest_hash === undefined\n\t\t\t\t\t\t? undefined\n\t\t\t\t\t\t: optionalViewerString(body, \"manifest_hash\"),\n\t\t\t\tstatus: body.status === undefined ? undefined : optionalViewerString(body, \"status\"),\n\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t});\n\t\t\tif (!scope) return c.json({ error: \"scope_not_found\", status }, 404);\n\t\t\treturn c.json({ ok: true, scope, group_id: groupId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message, status }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.get(\"/api/coordinator/admin/groups/:group_id/scopes/:scope_id/members\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tconst scopeId = String(c.req.param(\"scope_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (!scopeId) return c.json({ error: \"scope_id required\", status }, 400);\n\t\ttry {\n\t\t\tconst items = await coordinatorListScopeMembershipsAction({\n\t\t\t\tgroupId,\n\t\t\t\tscopeId,\n\t\t\t\tincludeRevoked: queryBool(c.req.query(\"include_revoked\")),\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, group_id: groupId, scope_id: scopeId, 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 }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/scopes/:scope_id/members\", async (c) => {\n\t\tconst config = readCoordinatorSyncConfig();\n\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\n\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tconst scopeId = String(c.req.param(\"scope_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tif (!scopeId) return c.json({ error: \"scope_id required\", status }, 400);\n\t\tconst body = await parseViewerJsonBody(c);\n\t\tif (!body) return c.json({ error: \"invalid json\", status }, 400);\n\t\tconst deviceId = optionalViewerString(body, \"device_id\");\n\t\tconst membershipEpoch = optionalViewerNumber(body, \"membership_epoch\");\n\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\tif (Number.isNaN(membershipEpoch)) {\n\t\t\treturn c.json({ error: \"membership_epoch must be number\", status }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst membership = await coordinatorGrantScopeMembershipAction({\n\t\t\t\tgroupId,\n\t\t\t\tscopeId,\n\t\t\t\tdeviceId,\n\t\t\t\trole: optionalViewerString(body, \"role\"),\n\t\t\t\tmembershipEpoch,\n\t\t\t\tcoordinatorId: optionalViewerString(body, \"coordinator_id\"),\n\t\t\t\tmanifestIssuerDeviceId: optionalViewerString(body, \"manifest_issuer_device_id\"),\n\t\t\t\tmanifestHash: optionalViewerString(body, \"manifest_hash\"),\n\t\t\t\tsignedManifestJson: optionalViewerString(body, \"signed_manifest_json\"),\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, membership, group_id: groupId, scope_id: scopeId, status });\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: message, status }, coordinatorAdminMutationStatus(message));\n\t\t}\n\t});\n\n\tapp.post(\n\t\t\"/api/coordinator/admin/groups/:group_id/scopes/:scope_id/members/:device_id/revoke\",\n\t\tasync (c) => {\n\t\t\tconst config = readCoordinatorSyncConfig();\n\t\t\tconst status = coordinatorAdminStatusPayload(config);\n\t\t\tconst unavailable = coordinatorAdminUnavailable(status);\n\t\t\tif (unavailable) return c.json(unavailable.body, unavailable.httpStatus);\n\t\t\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\t\tconst scopeId = String(c.req.param(\"scope_id\") ?? \"\").trim();\n\t\t\tconst deviceId = String(c.req.param(\"device_id\") ?? \"\").trim();\n\t\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\t\tif (!scopeId) return c.json({ error: \"scope_id required\", status }, 400);\n\t\t\tif (!deviceId) return c.json({ error: \"device_id required\", status }, 400);\n\t\t\tconst body = await parseViewerJsonBody(c, { allowEmpty: true });\n\t\t\tif (!body) return c.json({ error: \"invalid json\", status }, 400);\n\t\t\tconst membershipEpoch = optionalViewerNumber(body, \"membership_epoch\");\n\t\t\tif (Number.isNaN(membershipEpoch)) {\n\t\t\t\treturn c.json({ error: \"membership_epoch must be number\", status }, 400);\n\t\t\t}\n\t\t\ttry {\n\t\t\t\tconst ok = await coordinatorRevokeScopeMembershipAction({\n\t\t\t\t\tgroupId,\n\t\t\t\t\tscopeId,\n\t\t\t\t\tdeviceId,\n\t\t\t\t\tmembershipEpoch,\n\t\t\t\t\tmanifestHash: optionalViewerString(body, \"manifest_hash\"),\n\t\t\t\t\tsignedManifestJson: optionalViewerString(body, \"signed_manifest_json\"),\n\t\t\t\t\tremoteUrl: config.syncCoordinatorUrl || null,\n\t\t\t\t\tadminSecret: config.syncCoordinatorAdminSecret || null,\n\t\t\t\t});\n\t\t\t\tif (!ok) return c.json({ error: \"membership_not_found\", status }, 404);\n\t\t\t\treturn c.json({\n\t\t\t\t\tok: true,\n\t\t\t\t\tgroup_id: groupId,\n\t\t\t\t\tscope_id: scopeId,\n\t\t\t\t\tdevice_id: deviceId,\n\t\t\t\t\tstatus,\n\t\t\t\t});\n\t\t\t} catch (error) {\n\t\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\t\treturn c.json({ error: message, status }, coordinatorAdminMutationStatus(message));\n\t\t\t}\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 }, coordinatorAdminMutationStatus(message));\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\tlet defaultSpaceMembership = null;\n\t\t\tlet setupWarning = null;\n\t\t\ttry {\n\t\t\t\tdefaultSpaceMembership = await maybeGrantDefaultSpaceOnJoin({\n\t\t\t\t\tstore: getStore(),\n\t\t\t\t\tconfig,\n\t\t\t\t\tgroupId: result.group_id,\n\t\t\t\t\tdeviceId: result.device_id,\n\t\t\t\t});\n\t\t\t} catch (grantError) {\n\t\t\t\tsetupWarning = {\n\t\t\t\t\tstep: \"default_space_grant\",\n\t\t\t\t\terror: grantError instanceof Error ? grantError.message : String(grantError),\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\trequest: result,\n\t\t\t\tdefault_space_membership: defaultSpaceMembership,\n\t\t\t\tsetup_warning: setupWarning,\n\t\t\t\tstatus,\n\t\t\t});\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 }, coordinatorAdminMutationStatus(message));\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/enable\", 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 coordinatorEnableDeviceAction({\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\t// Unified peer-enrollment entry point. Mode is chosen by an explicit\n\t// body field so a legitimate coordinator group named (for example)\n\t// `none` cannot collide with the manual-pairing path:\n\t// - `mode: \"discovered\"` (default) → promote a coordinator-discovered\n\t// device, seed scope from the :group_id group's template when\n\t// auto_seed_scope is true and the caller didn't pass an override.\n\t// - `mode: \"manual\"` → manual pairing. Accepts peer_public_key +\n\t// optional name/fingerprint/addresses; :group_id path param is\n\t// ignored and both discovery columns are left null.\n\t// See docs/plans/2026-04-22-multi-team-coordinator-groups-design.md.\n\tapp.post(\"/api/coordinator/admin/groups/:group_id/enroll-peer\", 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\t// Admin-secret gating happens inside the discovered branch below —\n\t\t// manual pairing only writes a local sync_peers row and doesn't need\n\t\t// coordinator-admin privileges, matching the pre-existing /peers/accept\n\t\t// path.\n\t\tconst rawGroupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!rawGroupId) return c.json({ error: \"group_id required\" }, 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\" }, 400);\n\t\t}\n\t\tconst rawMode = String(body.mode ?? \"\")\n\t\t\t.trim()\n\t\t\t.toLowerCase();\n\t\tif (rawMode && rawMode !== \"manual\" && rawMode !== \"discovered\") {\n\t\t\treturn c.json(\n\t\t\t\t{ error: \"invalid_mode\", detail: `mode must be 'discovered' or 'manual', got ${rawMode}` },\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tconst mode: \"discovered\" | \"manual\" = rawMode === \"manual\" ? \"manual\" : \"discovered\";\n\t\t// Per-field normalization: distinguish \"caller did not specify\" from\n\t\t// \"caller set empty\". `undefined` = inherit (template); `null` or empty\n\t\t// array = explicit clear; non-empty array = use as-is.\n\t\tconst normalizeOverride = (value: unknown): string[] | null | undefined => {\n\t\t\tif (value === undefined) return undefined;\n\t\t\tif (value === null) return null;\n\t\t\tif (!Array.isArray(value)) return undefined;\n\t\t\tconst cleaned = value\n\t\t\t\t.map((item) => String(item ?? \"\").trim())\n\t\t\t\t.filter((item) => item.length > 0);\n\t\t\treturn cleaned.length === 0 ? null : cleaned;\n\t\t};\n\t\tconst overrideInclude = normalizeOverride(body.projects_include);\n\t\tconst overrideExclude = normalizeOverride(body.projects_exclude);\n\t\tconst scopeOverride =\n\t\t\toverrideInclude === undefined && overrideExclude === undefined\n\t\t\t\t? undefined\n\t\t\t\t: { projects_include: overrideInclude, projects_exclude: overrideExclude };\n\t\tconst store = getStore();\n\n\t\tif (mode === \"manual\") {\n\t\t\tconst peerDeviceId = String(body.peer_device_id ?? \"\").trim();\n\t\t\tconst publicKey = String(body.peer_public_key ?? \"\").trim();\n\t\t\tconst name = String(body.name ?? \"\").trim() || null;\n\t\t\tconst requestedFingerprint = String(body.fingerprint ?? \"\").trim();\n\t\t\tconst addressesInput = Array.isArray(body.peer_addresses) ? body.peer_addresses : [];\n\t\t\tconst addresses = mergeAddresses(\n\t\t\t\t[],\n\t\t\t\taddressesInput.map((item) => String(item ?? \"\").trim()).filter((item) => item.length > 0),\n\t\t\t);\n\t\t\tif (!peerDeviceId || !publicKey) {\n\t\t\t\treturn c.json({ error: \"peer_device_id_and_public_key_required\" }, 400);\n\t\t\t}\n\t\t\tconst fingerprint = requestedFingerprint || fingerprintPublicKey(publicKey);\n\t\t\tif (fingerprintPublicKey(publicKey) !== fingerprint) {\n\t\t\t\treturn c.json({ error: \"fingerprint_mismatch\" }, 400);\n\t\t\t}\n\t\t\tconst manualInclude =\n\t\t\t\toverrideInclude && overrideInclude.length > 0 ? JSON.stringify(overrideInclude) : null;\n\t\t\tconst manualExclude =\n\t\t\t\toverrideExclude && overrideExclude.length > 0 ? JSON.stringify(overrideExclude) : null;\n\t\t\tconst now = new Date().toISOString();\n\t\t\tconst d = drizzle(store.db, { schema });\n\t\t\t// Wrap the duplicate check + insert in a transaction so two concurrent\n\t\t\t// enrolls for the same peer cannot both clear the check. SQLite\n\t\t\t// serializes transactions on the write lock, so the second one sees\n\t\t\t// the committed row and returns 409 instead of racing past.\n\t\t\ttry {\n\t\t\t\tconst created = store.db.transaction(() => {\n\t\t\t\t\tconst existing = d\n\t\t\t\t\t\t.select({ peer_device_id: schema.syncPeers.peer_device_id })\n\t\t\t\t\t\t.from(schema.syncPeers)\n\t\t\t\t\t\t.where(eq(schema.syncPeers.peer_device_id, peerDeviceId))\n\t\t\t\t\t\t.get();\n\t\t\t\t\tif (existing) return false;\n\t\t\t\t\td.insert(schema.syncPeers)\n\t\t\t\t\t\t.values({\n\t\t\t\t\t\t\tpeer_device_id: peerDeviceId,\n\t\t\t\t\t\t\tname,\n\t\t\t\t\t\t\tpinned_fingerprint: fingerprint,\n\t\t\t\t\t\t\tpublic_key: publicKey,\n\t\t\t\t\t\t\taddresses_json: JSON.stringify(addresses),\n\t\t\t\t\t\t\tprojects_include_json: manualInclude,\n\t\t\t\t\t\t\tprojects_exclude_json: manualExclude,\n\t\t\t\t\t\t\tcreated_at: now,\n\t\t\t\t\t\t\tlast_seen_at: now,\n\t\t\t\t\t\t\tdiscovered_via_coordinator_id: null,\n\t\t\t\t\t\t\tdiscovered_via_group_id: null,\n\t\t\t\t\t\t})\n\t\t\t\t\t\t.run();\n\t\t\t\t\treturn true;\n\t\t\t\t})();\n\t\t\t\tif (!created) {\n\t\t\t\t\treturn c.json({ error: \"peer_exists\", detail: \"Peer is already enrolled.\" }, 409);\n\t\t\t\t}\n\t\t\t} catch (error) {\n\t\t\t\t// Primary-key constraint collision is the expected race signal; the\n\t\t\t\t// first writer wins, the second gets \"peer_exists\".\n\t\t\t\tconst msg = error instanceof Error ? error.message.toLowerCase() : \"\";\n\t\t\t\tif (msg.includes(\"unique\") || msg.includes(\"primary key\")) {\n\t\t\t\t\treturn c.json({ error: \"peer_exists\", detail: \"Peer is already enrolled.\" }, 409);\n\t\t\t\t}\n\t\t\t\tthrow error;\n\t\t\t}\n\t\t\treturn c.json({\n\t\t\t\tok: true,\n\t\t\t\tpeer_device_id: peerDeviceId,\n\t\t\t\tcreated: true,\n\t\t\t\tupdated: false,\n\t\t\t\tname,\n\t\t\t\tgroup_id: null,\n\t\t\t});\n\t\t}\n\n\t\t// Discovered mode calls out to the coordinator for reciprocal approval,\n\t\t// so it needs the admin secret. Manual mode never leaves this process.\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 peerDeviceId = String(body.peer_device_id ?? body.discovered_device_id ?? \"\").trim();\n\t\tconst fingerprint = String(body.fingerprint ?? \"\").trim();\n\t\tif (!peerDeviceId || !fingerprint) {\n\t\t\treturn c.json({ error: \"peer_device_id_and_fingerprint_required\" }, 400);\n\t\t}\n\t\ttry {\n\t\t\tconst result = await acceptDiscoveredPeer(store, {\n\t\t\t\tpeerDeviceId,\n\t\t\t\tfingerprint,\n\t\t\t\texpectedGroupId: rawGroupId,\n\t\t\t\tscopeOverride,\n\t\t\t});\n\t\t\tif (result.ok) {\n\t\t\t\treturn c.json(result);\n\t\t\t}\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: result.error,\n\t\t\t\t\tdetail: result.detail,\n\t\t\t\t\t...(result.reason ? { reason: result.reason } : {}),\n\t\t\t\t},\n\t\t\t\tresult.status as 400 | 404 | 409,\n\t\t\t);\n\t\t} catch (error) {\n\t\t\t// acceptDiscoveredPeer shells out to the coordinator for reciprocal\n\t\t\t// approval and can throw on timeout / network / auth failures. Map\n\t\t\t// those to a structured 502 so clients get the same shape as the\n\t\t\t// legacy /api/sync/peers/accept-discovered path.\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\t502,\n\t\t\t);\n\t\t}\n\t});\n\n\t// Local-only preferences for a coordinator group — project-scope template\n\t// + auto-seed toggle applied when peers are enrolled through the group.\n\t// See docs/plans/2026-04-22-multi-team-coordinator-groups-design.md.\n\t// Local-only preferences — these rows live in the viewer's own DB and never\n\t// cross the wire to the coordinator. No admin-secret gate: the admin secret\n\t// authorizes remote coordinator mutations, not local settings.\n\tapp.get(\"/api/coordinator/admin/groups/:group_id/preferences\", (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\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tconst coordinatorId = status.coordinator_url;\n\t\tif (!coordinatorId) return c.json({ error: \"coordinator_not_configured\", status }, 400);\n\t\tconst store = getStore();\n\t\tconst existing = getCoordinatorGroupPreference(store.db, coordinatorId, groupId);\n\t\tif (existing) return c.json({ preferences: existing, status });\n\t\treturn c.json({\n\t\t\tpreferences: {\n\t\t\t\tcoordinator_id: coordinatorId,\n\t\t\t\tgroup_id: groupId,\n\t\t\t\tprojects_include: null,\n\t\t\t\tprojects_exclude: null,\n\t\t\t\tauto_seed_scope: true,\n\t\t\t\tdefault_space_scope_id: null,\n\t\t\t\tauto_grant_default_space_on_join: false,\n\t\t\t\tupdated_at: null,\n\t\t\t},\n\t\t\tstatus,\n\t\t});\n\t});\n\n\tapp.put(\"/api/coordinator/admin/groups/:group_id/preferences\", 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\tconst groupId = String(c.req.param(\"group_id\") ?? \"\").trim();\n\t\tif (!groupId) return c.json({ error: \"group_id required\", status }, 400);\n\t\tconst coordinatorId = status.coordinator_url;\n\t\tif (!coordinatorId) return c.json({ error: \"coordinator_not_configured\", 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 normalizeList = (value: unknown): string[] | null | undefined => {\n\t\t\tif (value === undefined) return undefined;\n\t\t\tif (value === null) return null;\n\t\t\tif (!Array.isArray(value)) return undefined;\n\t\t\tconst cleaned = value\n\t\t\t\t.map((item) => String(item ?? \"\").trim())\n\t\t\t\t.filter((item) => item.length > 0);\n\t\t\treturn cleaned.length === 0 ? null : cleaned;\n\t\t};\n\t\tconst autoSeed = typeof body.auto_seed_scope === \"boolean\" ? body.auto_seed_scope : undefined;\n\t\tconst autoGrantDefaultSpace =\n\t\t\ttypeof body.auto_grant_default_space_on_join === \"boolean\"\n\t\t\t\t? body.auto_grant_default_space_on_join\n\t\t\t\t: undefined;\n\t\tconst defaultSpaceScopeId =\n\t\t\tbody.default_space_scope_id === undefined\n\t\t\t\t? undefined\n\t\t\t\t: optionalViewerString(body, \"default_space_scope_id\");\n\t\tif (autoGrantDefaultSpace === true && !defaultSpaceScopeId) {\n\t\t\treturn c.json(\n\t\t\t\t{\n\t\t\t\t\terror: \"default_space_scope_id_required_for_auto_grant\",\n\t\t\t\t\tstatus,\n\t\t\t\t},\n\t\t\t\t400,\n\t\t\t);\n\t\t}\n\t\tconst store = getStore();\n\t\ttry {\n\t\t\tconst preferences = upsertCoordinatorGroupPreference(store.db, {\n\t\t\t\tcoordinator_id: coordinatorId,\n\t\t\t\tgroup_id: groupId,\n\t\t\t\tprojects_include: normalizeList(body.projects_include),\n\t\t\t\tprojects_exclude: normalizeList(body.projects_exclude),\n\t\t\t\tauto_seed_scope: autoSeed,\n\t\t\t\tdefault_space_scope_id: defaultSpaceScopeId,\n\t\t\t\tauto_grant_default_space_on_join: autoGrantDefaultSpace,\n\t\t\t});\n\t\t\treturn c.json({ preferences, status });\n\t\t} catch (error) {\n\t\t\tconst msg = error instanceof Error ? error.message : String(error);\n\t\t\treturn c.json({ error: msg, 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(\"/assets/*\", async (c, next) => {\n\t\tc.header(\"Cache-Control\", \"no-cache\");\n\t\tawait next();\n\t});\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\tc.header(\"Cache-Control\", \"no-store\");\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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"}
|