import { g as getAllSubstrates, a as getAgentRegistryDb, b as getNexusDb, c as getConduitDb, d as getTasksDb, e as getBrainDb } from './src-DG3l2-J-.js';
import { b as buildCacheKey, g as getCachedGraph, r as recordBrainLoadDuration, a as getBrainCacheMetrics, s as setCachedGraph } from './brain-D3P07VKO.js';
import './dual-scope-db-ATrwq0LH.js';
import './paths-2M_UxD_H.js';
import 'node:fs';
import 'node:path';
import 'node:os';
import 'node:events';
import 'node:diagnostics_channel';
import 'fs';
import 'events';
import 'util';
import 'path';
import 'assert';
import 'worker_threads';
import 'module';
import 'node:url';
import 'url';
import 'buffer';
import 'node:module';
import 'node:child_process';
import 'node:crypto';
import 'node:process';
import 'node:async_hooks';
import './indexes-aYlULWG3.js';
import './utils-BvHPJOVk.js';

//#region src/lib/graph/adapters/cross-substrate.ts
/**
* Execute a prepared statement and cast to `T[]`.
* Identical to `allTyped` in `@cleocode/brain/db-connections` —
* duplicated here so the studio package stays independent.
*/
function allTyped(stmt, ...params) {
	return stmt.all(...params);
}
/** Default weight for all bridge edges — 0.7, higher than intra-substrate defaults. */
var BRIDGE_WEIGHT = .7;
/**
* Translate a `brain_memory_links.link_type` value to the canonical
* `EdgeKind` vocabulary.
*
* Known values per `BRAIN_LINK_TYPES` in memory-schema.ts:
* `produced_by | applies_to | informed_by | contradicts`
*
* @param linkType - Raw link_type from brain_memory_links.
* @returns Canonical EdgeKind.
*/
function memLinkToEdgeKind(linkType) {
	if (linkType === "produced_by") return "produced_by";
	if (linkType === "informed_by") return "informed_by";
	if (linkType === "applies_to") return "derived_from";
	if (linkType === "contradicts") return "relates_to";
	return "relates_to";
}
/**
* Returns true when a `brain_page_edges.to_id` value looks like a nexus
* node path (contains `::` separator for file::Symbol, or is a relative
* file path with a `/`).
*
* Mirrors `isNexusStyleId` from `packages/brain/src/adapters/brain.ts`.
*
* @param toId - Candidate ID string from brain_page_edges.
*/
function isNexusStyleId(toId) {
	if (toId.includes("::")) return true;
	if (!toId.includes(":") && toId.includes("/")) return true;
	return false;
}
/**
* Returns true when a `brain_page_edges.from_id` / `to_id` value represents
* a task reference (e.g. `"task:T532"`).
*
* @param id - Candidate ID string from brain_page_edges.
*/
function isTaskRef(id) {
	return id.startsWith("task:");
}
/**
* Returns true when a `brain_page_edges.from_id` value represents
* a CONDUIT message reference (e.g. `"msg:msg_abc123"`).
*
* @param id - Candidate ID string from brain_page_edges.
*/
function isMsgRef(id) {
	return id.startsWith("msg:");
}
/**
* Compute all cross-substrate bridges between the given node set.
*
* This is the primary integration point for Agent C's server load. It
* is called for tier-0, tier-1, and tier-2 paints. Bridges involving
* hub nodes are always included — even in tier-0 — because bridges are
* what makes the first paint look "alive".
*
* The function:
* 1. Enumerates each bridge category using SQL queries against the provided DBs.
* 2. Filters to bridges where both endpoints exist in `nodes`.
* 3. Deduplicates by (source, target, kind).
* 4. Applies a 2 × |nodes| cap, sorted by weight descending.
* 5. Logs per-category counts to `console.info`.
*
* @param nodes - Current node set (substrate-prefixed IDs). Only bridges
*   where both endpoints appear here are emitted.
* @param dbRefs - Optional DB connections. Missing DBs produce zero bridges
*   for that category — no errors are thrown.
* @returns Array of {@link GraphEdge} objects with `meta.isBridge: true`.
*
* @example
* ```ts
* import { computeBridges } from '$lib/graph/adapters/cross-substrate.js';
*
* const bridges = computeBridges(nodes, { brainDb, tasksDb, nexusDb });
* const allEdges = [...intraEdges, ...bridges];
* ```
*/
function computeBridges(nodes, dbRefs) {
	const nodeIdSet = new Set(nodes.map((n) => n.id));
	const raw = [];
	if (dbRefs.brainDb) {
		raw.push(...bridgeTaskBrainViaMemLinks(dbRefs.brainDb, nodeIdSet));
		raw.push(...bridgeTaskBrainViaDecisions(dbRefs.brainDb, nodeIdSet));
	}
	if (dbRefs.brainDb) {
		raw.push(...bridgeBrainNexusViaPageEdges(dbRefs.brainDb, nodeIdSet));
		raw.push(...bridgeBrainNexusViaObsFiles(dbRefs.brainDb, nodeIdSet));
	}
	if (dbRefs.brainDb) raw.push(...bridgeConduitTasksViaPageEdges(dbRefs.brainDb, nodeIdSet));
	if (dbRefs.tasksDb) raw.push(...bridgeAgentRegistryTasksViaAssignee(dbRefs.tasksDb, nodeIdSet));
	const seen = /* @__PURE__ */ new Set();
	const unique = [];
	for (const b of raw) {
		const key = `${b.source}|${b.target}|${b.kind}`;
		if (!seen.has(key)) {
			seen.add(key);
			unique.push(b);
		}
	}
	const cap = nodes.length * 2;
	unique.sort((a, b) => b.weight - a.weight);
	const capped = unique.length > cap;
	const result = capped ? unique.slice(0, cap) : unique;
	const stats = buildStats(result, capped);
	console.info(`[cross-substrate] bridges emitted: ${stats.total} (capped=${stats.capped}) — ` + Object.entries(stats.byType).filter(([, v]) => v > 0).map(([k, v]) => `${k}:${v}`).join(", "));
	return result.map((b, i) => ({
		id: `bridge-${i}:${b.source}>${b.target}:${b.kind}`,
		source: b.source,
		target: b.target,
		kind: b.kind,
		weight: b.weight,
		directional: true,
		meta: b.meta
	}));
}
/**
* Bridge: TASK ↔ BRAIN via `brain_memory_links`.
*
* The `brain_memory_links` table stores explicit cross-DB links between
* typed memory entries and tasks. Each row maps (memory_type, memory_id) →
* task_id with a semantic link_type.
*
* Verified present in `memory-schema.ts` as `brainMemoryLinks`.
*
* @param db - brain.db connection.
* @param nodeIds - Set of loaded node IDs.
* @returns Bridge edges.
*/
function bridgeTaskBrainViaMemLinks(db, nodeIds) {
	const bridges = [];
	try {
		const rows = allTyped(db.prepare(`SELECT memory_type, memory_id, task_id, link_type
         FROM brain_memory_links
         LIMIT 2000`));
		for (const row of rows) {
			const brainNodeId = `brain:${row.memory_id}`;
			const tasksNodeId = `tasks:${row.task_id}`;
			if (!nodeIds.has(brainNodeId) || !nodeIds.has(tasksNodeId)) continue;
			const kind = memLinkToEdgeKind(row.link_type);
			bridges.push({
				source: brainNodeId,
				target: tasksNodeId,
				kind,
				weight: BRIDGE_WEIGHT,
				meta: {
					isBridge: true,
					bridgeType: "task->brain",
					description: `Memory entry ${row.memory_type}:${row.memory_id} ${kind.replace("_", " ")} task ${row.task_id}`,
					link_type: row.link_type,
					memory_type: row.memory_type
				}
			});
		}
	} catch {}
	return bridges;
}
/**
* Bridge: TASK ↔ BRAIN via `brain_decisions.context_task_id` and
* `brain_decisions.context_epic_id`.
*
* Both columns are present in the schema as soft FKs into tasks.db.
* Each decision that cites a task gets an `informed_by` bridge pointing
* to the task that provided the architectural context.
*
* Verified present in `memory-schema.ts` as `brainDecisions.contextTaskId`
* and `brainDecisions.contextEpicId`.
*
* @param db - brain.db connection.
* @param nodeIds - Set of loaded node IDs.
* @returns Bridge edges.
*/
function bridgeTaskBrainViaDecisions(db, nodeIds) {
	const bridges = [];
	try {
		const rows = allTyped(db.prepare(`SELECT id, context_task_id, context_epic_id
         FROM brain_decisions
         WHERE context_task_id IS NOT NULL OR context_epic_id IS NOT NULL
         LIMIT 1000`));
		for (const row of rows) {
			const brainNodeId = `brain:${row.id}`;
			if (!nodeIds.has(brainNodeId)) continue;
			if (row.context_task_id) {
				const tasksNodeId = `tasks:${row.context_task_id}`;
				if (nodeIds.has(tasksNodeId)) bridges.push({
					source: brainNodeId,
					target: tasksNodeId,
					kind: "informed_by",
					weight: BRIDGE_WEIGHT,
					meta: {
						isBridge: true,
						bridgeType: "task->brain",
						description: `Decision informed by task ${row.context_task_id}`,
						context_column: "context_task_id"
					}
				});
			}
			if (row.context_epic_id) {
				const tasksNodeId = `tasks:${row.context_epic_id}`;
				if (nodeIds.has(tasksNodeId)) bridges.push({
					source: brainNodeId,
					target: tasksNodeId,
					kind: "informed_by",
					weight: BRIDGE_WEIGHT,
					meta: {
						isBridge: true,
						bridgeType: "task->brain",
						description: `Decision informed by epic ${row.context_epic_id}`,
						context_column: "context_epic_id"
					}
				});
			}
		}
	} catch {}
	return bridges;
}
/**
* Bridge: BRAIN ↔ NEXUS via `brain_page_edges` where `to_id` is a nexus path.
*
* `brain_page_edges.to_id` may store nexus-style IDs:
* - `"some/path/file.ts::SymbolName"` — a file::Symbol reference
* - `"some/relative/path.ts"` — a file path (no `:` prefix)
*
* These map to `nexus:<to_id>` in the graph. The existing brain.ts adapter
* already emits some of these in its `BrainEdge` output; this function
* surfaces the same bridges at the Studio adapter layer so they flow through
* the `computeBridges` path and carry `meta.isBridge: true`.
*
* @param db - brain.db connection.
* @param nodeIds - Set of loaded node IDs.
* @returns Bridge edges.
*/
function bridgeBrainNexusViaPageEdges(db, nodeIds) {
	const bridges = [];
	try {
		const rows = allTyped(db.prepare(`SELECT from_id, to_id, edge_type, weight
         FROM brain_page_edges
         LIMIT 5000`));
		for (const row of rows) {
			if (!isNexusStyleId(row.to_id)) continue;
			const sep = row.from_id.indexOf(":");
			if (sep === -1) continue;
			const prefix = row.from_id.slice(0, sep);
			const rawId = row.from_id.slice(sep + 1);
			if (!new Set([
				"observation",
				"decision",
				"pattern",
				"learning"
			]).has(prefix)) continue;
			const brainNodeId = `brain:${rawId}`;
			const nexusNodeId = `nexus:${row.to_id}`;
			if (!nodeIds.has(brainNodeId) || !nodeIds.has(nexusNodeId)) continue;
			bridges.push({
				source: brainNodeId,
				target: nexusNodeId,
				kind: "references",
				weight: Math.min(1, Math.max(.1, row.weight ?? BRIDGE_WEIGHT)),
				meta: {
					isBridge: true,
					bridgeType: "brain->nexus",
					description: `Brain node ${prefix}:${rawId} references code ${row.to_id}`,
					edge_type: row.edge_type,
					link_kind: "code"
				}
			});
		}
	} catch {}
	return bridges;
}
/**
* Bridge: BRAIN ↔ NEXUS via `brain_observations.files_modified_json`.
*
* Each observation can carry a JSON array of relative file paths it
* modified during the session. Each path maps to `nexus:<path>`.
*
* Cap: first 5 links per observation to prevent hairballing on
* large session observations.
*
* Verified present in `memory-schema.ts` as `brainObservations.filesModifiedJson`.
*
* @param db - brain.db connection.
* @param nodeIds - Set of loaded node IDs.
* @returns Bridge edges.
*/
function bridgeBrainNexusViaObsFiles(db, nodeIds) {
	const bridges = [];
	const MAX_LINKS_PER_OBS = 5;
	try {
		const rows = allTyped(db.prepare(`SELECT id, files_modified_json
         FROM brain_observations
         WHERE files_modified_json IS NOT NULL
           AND files_modified_json != '[]'
         LIMIT 500`));
		for (const row of rows) {
			if (!row.files_modified_json) continue;
			const brainNodeId = `brain:${row.id}`;
			if (!nodeIds.has(brainNodeId)) continue;
			let filePaths;
			try {
				filePaths = JSON.parse(row.files_modified_json);
			} catch {
				continue;
			}
			if (!Array.isArray(filePaths)) continue;
			const limited = filePaths.slice(0, MAX_LINKS_PER_OBS);
			for (const rawPath of limited) {
				if (typeof rawPath !== "string" || rawPath.length === 0) continue;
				const nexusNodeId = `nexus:${rawPath}`;
				if (!nodeIds.has(nexusNodeId)) continue;
				bridges.push({
					source: brainNodeId,
					target: nexusNodeId,
					kind: "documents",
					weight: BRIDGE_WEIGHT,
					meta: {
						isBridge: true,
						bridgeType: "brain->nexus",
						description: `Observation documents file ${rawPath}`,
						file_path: rawPath
					}
				});
			}
		}
	} catch {}
	return bridges;
}
/**
* Bridge: CONDUIT ↔ TASKS via `brain_page_edges` where `from_id` is a
* `msg:` reference and `to_id` is a `task:` reference.
*
* `brain_page_edges` stores cross-substrate links at the page-graph level.
* The `discusses` edge type (defined in `BRAIN_EDGE_TYPES`) connects
* CONDUIT message nodes to task nodes.
*
* The `conduit:` node prefix is used in the graph even though the
* page-edge stores `msg:` as the type prefix. Conversion:
* - `msg:<messageId>` → `conduit:<messageId>`
* - `task:<taskId>` → `tasks:<taskId>`
*
* @param db - brain.db connection (page edges cross-reference conduit).
* @param nodeIds - Set of loaded node IDs.
* @returns Bridge edges.
*/
function bridgeConduitTasksViaPageEdges(db, nodeIds) {
	const bridges = [];
	try {
		const rows = allTyped(db.prepare(`SELECT from_id, to_id, edge_type, weight
         FROM brain_page_edges
         WHERE from_id LIKE 'msg:%'
           AND to_id LIKE 'task:%'
         LIMIT 1000`));
		for (const row of rows) {
			if (!isMsgRef(row.from_id) || !isTaskRef(row.to_id)) continue;
			const msgId = row.from_id.slice(4);
			const taskId = row.to_id.slice(5);
			const conduitNodeId = `conduit:${msgId}`;
			const tasksNodeId = `tasks:${taskId}`;
			if (!nodeIds.has(conduitNodeId) || !nodeIds.has(tasksNodeId)) continue;
			bridges.push({
				source: conduitNodeId,
				target: tasksNodeId,
				kind: "messages",
				weight: BRIDGE_WEIGHT,
				meta: {
					isBridge: true,
					bridgeType: "conduit->tasks",
					description: `Conduit message discusses task ${taskId}`,
					edge_type: row.edge_type
				}
			});
		}
	} catch {}
	return bridges;
}
/**
* Bridge: SIGNALDOCK ↔ TASKS via `tasks.assignee` matching a loaded
* signaldock agent node.
*
* When a task has an `assignee` field and a signaldock node with that
* agent ID exists in the loaded node set, emit a `messages` bridge
* from the agent to the task.
*
* The `tasks.assignee` column is verified present in `tasks-schema.ts`.
* The signaldock node ID format is `agent-registry:<agent_id>`.
*
* @param db - tasks.db connection.
* @param nodeIds - Set of loaded node IDs.
* @returns Bridge edges.
*/
function bridgeAgentRegistryTasksViaAssignee(db, nodeIds) {
	const bridges = [];
	try {
		const rows = allTyped(db.prepare(`SELECT id, assignee
         FROM tasks
         WHERE assignee IS NOT NULL
           AND status NOT IN ('archived', 'cancelled')
         LIMIT 1000`));
		for (const row of rows) {
			if (!row.assignee) continue;
			const tasksNodeId = `tasks:${row.id}`;
			const signaldockNodeId = `agent-registry:${row.assignee}`;
			if (!nodeIds.has(tasksNodeId) || !nodeIds.has(signaldockNodeId)) continue;
			bridges.push({
				source: signaldockNodeId,
				target: tasksNodeId,
				kind: "messages",
				weight: BRIDGE_WEIGHT,
				meta: {
					isBridge: true,
					bridgeType: "signaldock->tasks",
					description: `Agent ${row.assignee} is assigned to task ${row.id}`,
					assignee: row.assignee
				}
			});
		}
	} catch {}
	return bridges;
}
/**
* Build {@link BridgeStats} from an array of bridge edges.
*
* @param bridges - The final emitted bridge set.
* @param capped - Whether the 2 × node-count cap was applied.
* @returns Statistics summary.
*/
function buildStats(bridges, capped) {
	const byType = {
		"task->brain": 0,
		"task->nexus": 0,
		"brain->nexus": 0,
		"conduit->tasks": 0,
		"conduit->brain": 0,
		"signaldock->tasks": 0,
		"signaldock->brain": 0
	};
	for (const b of bridges) {
		const bt = b.meta.bridgeType;
		byType[bt] = (byType[bt] ?? 0) + 1;
	}
	return {
		total: bridges.length,
		byType,
		capped
	};
}
//#endregion
//#region src/routes/brain/+page.server.ts
/**
* Brain canvas page server load (`/brain`) — progressive-disclosure edition.
*
* ## Performance strategy (T990)
*
* The prior implementation called `getAllSubstrates({ limit: 5000 })` on every
* request, serialising all 2000-5000 nodes into the SvelteKit payload before
* the browser received the first byte.  This produced a 3-8 second blank
* screen.
*
* The new strategy ships a **tier-0 payload** (top-200 hub nodes, < 200 ms)
* so the renderer can mount and paint a meaningful brain shape immediately.
* The client then fetches tier-1 (up to 1000 nodes) and tier-2 (remaining,
* up to 5000) from `/api/brain?tier=N` in the background.
*
* ### Tier sizes
*
* | Tier | Nodes | Target latency |
* |------|-------|----------------|
* | 0    | 200   | < 200 ms p95   |
* | 1    | 1000  | < 1000 ms      |
* | 2    | 5000  | < 3000 ms      |
*
* Tier 0 is served from an in-memory LRU cache (30-second TTL, 5 entries)
* so repeated navigations are < 30 ms.
*
* ### Client streaming helper
*
* The page exports {@link streamRemainingNodes} — an async function that Agent
* E's page shell calls from `onMount` to fetch tier-1 and tier-2 progressively.
* The function is exported from this module so the page only needs to import
* it once; it does NOT run on the server.
*
* @module
* @task T990
*/
/**
* Node cap for tier-0 first paint.
*
* Tuned (2026-04-19) after observing that `limit: 5000` produced a 30-45s
* freeze on first load — five sequential SQLite queries + the stub loader
* + cross-substrate bridge queries + 5000-node JSON serialisation blew
* past the time-to-interactive budget.
*
* `1500` balances three constraints:
*
*   - **Complete-enough visual**: with Agent D's cross-substrate bridges
*     wired, 1500 nodes already look like a full brain — the operator's
*     "missing data" complaint was about bridges being dead code, not
*     node counts.
*   - **First paint < 3s** on a cold cache even with bridges in-line.
*   - **Cached repeats < 30ms** via the LRU — same as before.
*
* Client-side streaming (`streamRemainingNodes()`) can pull tier-1 and
* tier-2 later if the operator wants the long tail; it stays opt-in.
*/
var TIER0_LIMIT = 1500;
/**
* Disable SSR for the brain canvas route.
*
* The Three.js / WebGL renderer imports browser-only APIs at module load
* time, making SSR impossible without significant shim complexity.  The
* route has no meaningful static content, so disabling SSR costs nothing
* and keeps the server clean.
*/
var ssr = false;
/**
* Compute cross-substrate bridge edges for the given graph.
*
* Wraps Agent D's {@link computeBridges} with the DB handles obtained
* from `@cleocode/brain`. Returns an empty array if the project context
* is missing or the DBs can't be opened.
*/
function computeBridgesForGraph(graph, ctx) {
	if (!ctx) return [];
	const kitNodes = graph.nodes.map((n) => ({
		id: n.id,
		substrate: n.substrate,
		kind: n.kind,
		label: n.label
	}));
	try {
		return computeBridges(kitNodes, {
			brainDb: getBrainDb(ctx) ?? void 0,
			tasksDb: getTasksDb(ctx) ?? void 0,
			conduitDb: getConduitDb(ctx) ?? void 0,
			nexusDb: getNexusDb() ?? void 0,
			signaldockDb: getAgentRegistryDb() ?? void 0
		});
	} catch (err) {
		console.warn("[brain/load] bridge computation failed:", err);
		return [];
	}
}
var load = ({ locals }) => {
	const t0 = performance.now();
	const cacheKey = buildCacheKey({
		projectId: locals.projectCtx?.projectId ?? "",
		limit: TIER0_LIMIT
	});
	const cached = getCachedGraph(cacheKey);
	if (cached) {
		const elapsed = performance.now() - t0;
		recordBrainLoadDuration(0, elapsed);
		const bridges = computeBridgesForGraph(cached, locals.projectCtx);
		const metrics = getBrainCacheMetrics();
		console.info(`[brain/load] tier=0 source=cache elapsed=${elapsed.toFixed(1)}ms bridges=${bridges.length} hits=${metrics.hits} misses=${metrics.misses} size=${metrics.size}`);
		return {
			graph: cached,
			bridges,
			fromCache: true,
			totalNodeCount: cached.truncated ? 5e3 : cached.nodes.length
		};
	}
	const graph = getAllSubstrates({
		limit: TIER0_LIMIT,
		projectCtx: locals.projectCtx
	});
	setCachedGraph(cacheKey, graph);
	const bridges = computeBridgesForGraph(graph, locals.projectCtx);
	const elapsed = performance.now() - t0;
	recordBrainLoadDuration(0, elapsed);
	const metrics = getBrainCacheMetrics();
	console.info(`[brain/load] tier=0 source=db elapsed=${elapsed.toFixed(1)}ms nodes=${graph.nodes.length} bridges=${bridges.length} hits=${metrics.hits} misses=${metrics.misses}`);
	return {
		graph,
		bridges,
		fromCache: false,
		totalNodeCount: graph.truncated ? 5e3 : graph.nodes.length
	};
};

var _page_server_ts = /*#__PURE__*/Object.freeze({
	__proto__: null,
	load: load,
	ssr: ssr
});

const index = 3;
let component_cache;
const component = async () => component_cache ??= (await import('./_page.svelte-8fLXUNL5.js')).default;
const server_id = "src/routes/brain/+page.server.ts";
const imports = ["_app/immutable/nodes/3.BJ9OZ72u.js","_app/immutable/chunks/o1PZ6Kzq.js","_app/immutable/chunks/DyGQ_VXC.js","_app/immutable/chunks/DrKWWDpL.js","_app/immutable/chunks/CQCxd1p9.js","_app/immutable/chunks/Dx6lY47C.js","_app/immutable/chunks/CQQRJ2Hr.js","_app/immutable/chunks/Bxz2A0ZC.js","_app/immutable/chunks/djL6V-tr.js","_app/immutable/chunks/RptFUp2P.js","_app/immutable/chunks/CEqOYim7.js"];
const stylesheets = ["_app/immutable/assets/cluster-label-layer.aRgASjnn.css","_app/immutable/assets/no-face-up.BlswZ73M.css","_app/immutable/assets/ThreeBrainRenderer.BSwu9fuL.css","_app/immutable/assets/Tabs.CU9_rsWl.css","_app/immutable/assets/3.DqDkvXKx.css"];
const fonts = [];

export { component, fonts, imports, index, _page_server_ts as server, server_id, stylesheets };
//# sourceMappingURL=3-t7r9BLiH.js.map
