@graph-tl/graph 0.1.10 → 0.1.14

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.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/server.ts","../src/tools/open.ts","../src/edges.ts","../src/tools/plan.ts","../src/tools/update.ts","../src/tools/connect.ts","../src/tools/context.ts","../src/tools/query.ts","../src/tools/next.ts","../src/tools/restructure.ts","../src/tools/history.ts","../src/tools/onboard.ts","../src/tools/tree.ts","../src/tools/knowledge.ts","../src/gates.ts"],"sourcesContent":["import { Server } from \"@modelcontextprotocol/sdk/server/index.js\";\nimport { StdioServerTransport } from \"@modelcontextprotocol/sdk/server/stdio.js\";\nimport {\n CallToolRequestSchema,\n ListToolsRequestSchema,\n ListResourcesRequestSchema,\n ListResourceTemplatesRequestSchema,\n ReadResourceRequestSchema,\n} from \"@modelcontextprotocol/sdk/types.js\";\nimport { setDbPath, closeDb, checkpointDb } from \"./db.js\";\nimport { ValidationError, EngineError } from \"./validate.js\";\nimport { handleOpen } from \"./tools/open.js\";\nimport { handlePlan } from \"./tools/plan.js\";\nimport { handleUpdate } from \"./tools/update.js\";\nimport { handleConnect } from \"./tools/connect.js\";\nimport { handleContext } from \"./tools/context.js\";\nimport { handleQuery } from \"./tools/query.js\";\nimport { handleNext } from \"./tools/next.js\";\nimport { handleRestructure } from \"./tools/restructure.js\";\nimport { handleHistory } from \"./tools/history.js\";\nimport { handleOnboard } from \"./tools/onboard.js\";\nimport { handleAgentConfig } from \"./tools/agent-config.js\";\nimport { handleTree } from \"./tools/tree.js\";\nimport { handleKnowledgeWrite, handleKnowledgeRead, handleKnowledgeDelete, handleKnowledgeSearch } from \"./tools/knowledge.js\";\nimport { getLicenseTier, type Tier } from \"./license.js\";\nimport { checkNodeLimit, checkProjectLimit, capEvidenceLimit, checkScope, checkKnowledgeTier } from \"./gates.js\";\n\nimport { createHash } from \"crypto\";\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { join, resolve, dirname } from \"path\";\nimport { fileURLToPath } from \"url\";\n\n// Config from env\nconst AGENT_IDENTITY = process.env.GRAPH_AGENT ?? \"default-agent\";\nconst CLAIM_TTL = parseInt(process.env.GRAPH_CLAIM_TTL ?? \"60\", 10);\n\nfunction defaultDbPath(): string {\n const projectDir = resolve(\".\");\n const hash = createHash(\"sha256\").update(projectDir).digest(\"hex\").slice(0, 16);\n const dir = join(homedir(), \".graph\", \"db\", hash);\n mkdirSync(dir, { recursive: true });\n return join(dir, \"graph.db\");\n}\n\nconst DB_PATH = process.env.GRAPH_DB ?? defaultDbPath();\n\n// Read version from package.json\nconst PKG_NAME = \"@graph-tl/graph\";\nlet PKG_VERSION = \"0.0.0\";\ntry {\n const __dirname = dirname(fileURLToPath(import.meta.url));\n const pkg = JSON.parse(readFileSync(join(__dirname, \"..\", \"package.json\"), \"utf-8\"));\n PKG_VERSION = pkg.version;\n} catch {}\n\n// Version banner — shown once on first tool call\nlet versionBanner: string | null = `[graph] v${PKG_VERSION}`;\n\n// Non-blocking version check against npm registry\nlet updateWarning: string | null = null;\n\nasync function checkForUpdate(): Promise<void> {\n try {\n const res = await fetch(`https://registry.npmjs.org/${PKG_NAME}/latest`);\n if (!res.ok) return;\n const data = await res.json() as { version: string };\n if (data.version !== PKG_VERSION) {\n updateWarning = `[graph] Update available: ${PKG_VERSION} → ${data.version}. Run: npx clear-npx-cache && restart MCP server.`;\n }\n } catch {}\n}\n\n// Auto-update agent file on first tool call\nfunction checkAndUpdateAgentFile(): string | null {\n try {\n const projectRoot = resolve(\".\");\n const agentPath = join(projectRoot, \".claude\", \"agents\", \"graph.md\");\n const latest = handleAgentConfig(PKG_VERSION).agent_file;\n\n if (existsSync(agentPath)) {\n const current = readFileSync(agentPath, \"utf-8\");\n if (current === latest) return null;\n // Extract version from existing frontmatter\n const match = current.match(/^---[\\s\\S]*?version:\\s*(\\S+)[\\s\\S]*?---/);\n const oldVersion = match?.[1] ?? \"unknown\";\n writeFileSync(agentPath, latest, \"utf-8\");\n return `[graph] Updated .claude/agents/graph.md (${oldVersion} → ${PKG_VERSION})`;\n } else {\n mkdirSync(dirname(agentPath), { recursive: true });\n writeFileSync(agentPath, latest, \"utf-8\");\n return `[graph] Created .claude/agents/graph.md`;\n }\n } catch {\n return null;\n }\n}\n\n// Tool definitions\nconst TOOLS = [\n {\n name: \"graph_open\",\n description:\n \"Open an existing project or create a new one. Omit 'project' to list all projects. Returns project root node and summary stats (total, resolved, unresolved, blocked, actionable counts).\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: {\n type: \"string\",\n description: \"Project name (e.g. 'my-project'). Omit to list all projects.\",\n },\n goal: {\n type: \"string\",\n description: \"Project goal/description. Used on creation only.\",\n },\n skip_discovery: {\n type: \"boolean\",\n description: \"Skip discovery phase — create project ready for immediate planning. Default false.\",\n },\n },\n },\n },\n {\n name: \"graph_plan\",\n description:\n \"Batch create nodes with parent-child and dependency relationships in one atomic call. Use for decomposing work into subtrees. Each node needs a temp 'ref' for intra-batch references. parent_ref and depends_on can reference batch refs or existing node IDs.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n nodes: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n ref: {\n type: \"string\",\n description: \"Temp ID for referencing within this batch\",\n },\n parent_ref: {\n type: \"string\",\n description:\n \"Parent: a ref from this batch OR an existing node ID\",\n },\n summary: { type: \"string\" },\n context_links: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Pointers to files, commits, URLs\",\n },\n depends_on: {\n type: \"array\",\n items: { type: \"string\" },\n description:\n \"Refs within batch OR existing node IDs this depends on\",\n },\n properties: {\n type: \"object\",\n description: \"Freeform key-value properties\",\n },\n },\n required: [\"ref\", \"summary\"],\n },\n description: \"Nodes to create\",\n },\n },\n required: [\"nodes\"],\n },\n },\n {\n name: \"graph_next\",\n description:\n \"Get the next actionable node — an unresolved leaf with all dependencies resolved. Ranked by priority (from properties), depth, and least-recently-updated. Returns the node with ancestor chain, context links, and resolved dependency info. Use claim=true to soft-lock the node. When modifying code for this task, annotate key changes with // [sl:nodeId] so future agents can trace code back to this task.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: { type: \"string\", description: \"Project name (e.g. 'my-project'), not a node ID\" },\n scope: {\n type: \"string\",\n description: \"Node ID to scope results to. Only returns actionable descendants of this node.\",\n },\n filter: {\n type: \"object\",\n description: \"Match against node properties\",\n },\n count: {\n type: \"number\",\n description: \"Return top N nodes (default 1)\",\n },\n claim: {\n type: \"boolean\",\n description:\n \"If true, soft-lock returned nodes with agent identity\",\n },\n },\n required: [\"project\"],\n },\n },\n {\n name: \"graph_context\",\n description:\n \"Deep-read a node and its neighborhood: ancestors (scope chain), children tree (to configurable depth), dependency graph (what it depends on, what depends on it). Look for // [sl:nodeId] annotations in source files to find code tied to specific tasks.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n node_id: { type: \"string\", description: \"Node ID to inspect\" },\n depth: {\n type: \"number\",\n description: \"Levels of children to return (default 2)\",\n },\n },\n required: [\"node_id\"],\n },\n },\n {\n name: \"graph_update\",\n description:\n \"Update one or more nodes. Can change resolved, state, summary, properties (merged), context_links, and add evidence. When resolving nodes, returns newly_actionable — nodes that became unblocked. ENFORCED: Resolving a node requires evidence — use resolved_reason (shorthand, auto-creates note) or add_evidence array (type: 'git' for commits, 'note' for what was done and why, 'test' for results). Also add context_links to files you modified.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n updates: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n node_id: { type: \"string\" },\n expected_rev: { type: \"number\", description: \"Optimistic concurrency: reject if node's current rev doesn't match. Prevents silent overwrites by concurrent agents.\" },\n resolved: { type: \"boolean\" },\n resolved_reason: { type: \"string\", description: \"Shorthand: auto-creates a note evidence entry. Use instead of add_evidence for simple cases.\" },\n discovery: { type: \"string\", description: \"Discovery phase status: 'pending' or 'done'. Set to 'done' after completing discovery interview.\" },\n blocked: { type: \"boolean\", description: \"Manually block/unblock a node. Blocked nodes are skipped by graph_next. Use for external blockers (e.g., waiting on domain purchase, another team).\" },\n blocked_reason: { type: \"string\", description: \"Why the node is blocked. Cleared automatically when unblocking.\" },\n state: { description: \"Agent-defined state, any type\" },\n summary: { type: \"string\" },\n properties: {\n type: \"object\",\n description:\n \"Merged into existing. Set a key to null to delete it.\",\n },\n add_context_links: {\n type: \"array\",\n items: { type: \"string\" },\n description: \"Files modified or created for this task. Add when resolving so future agents know what was touched.\",\n },\n remove_context_links: {\n type: \"array\",\n items: { type: \"string\" },\n },\n add_evidence: {\n type: \"array\",\n description: \"Evidence of work done. Always add when resolving. Types: 'git' (commit hash + summary), 'note' (what was implemented and why), 'test' (test results).\",\n items: {\n type: \"object\",\n properties: {\n type: { type: \"string\", description: \"Evidence type: git, note, test, or custom\" },\n ref: { type: \"string\", description: \"The evidence content — commit ref, implementation note, test result\" },\n },\n required: [\"type\", \"ref\"],\n },\n },\n },\n required: [\"node_id\"],\n },\n },\n },\n required: [\"updates\"],\n },\n },\n {\n name: \"graph_connect\",\n description:\n \"Add or remove edges between nodes. Types: 'depends_on' (with cycle detection), 'relates_to', or custom. Parent edges not allowed — use graph_restructure for reparenting.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n edges: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n from: { type: \"string\", description: \"Source node ID\" },\n to: { type: \"string\", description: \"Target node ID\" },\n type: {\n type: \"string\",\n description: \"'depends_on', 'relates_to', or custom\",\n },\n remove: {\n type: \"boolean\",\n description: \"True to remove this edge\",\n },\n },\n required: [\"from\", \"to\", \"type\"],\n },\n },\n },\n required: [\"edges\"],\n },\n },\n {\n name: \"graph_query\",\n description:\n \"Search and filter nodes. Filters: resolved, properties, text, ancestor (descendants of), is_leaf, is_actionable, is_blocked, claimed_by. Supports sorting and cursor pagination.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: { type: \"string\", description: \"Project name (e.g. 'my-project'), not a node ID\" },\n filter: {\n type: \"object\",\n properties: {\n resolved: { type: \"boolean\" },\n properties: { type: \"object\" },\n text: { type: \"string\", description: \"Substring match on summary\" },\n ancestor: {\n type: \"string\",\n description: \"Return all descendants of this node\",\n },\n has_evidence_type: { type: \"string\" },\n is_leaf: { type: \"boolean\" },\n is_actionable: { type: \"boolean\" },\n is_blocked: { type: \"boolean\" },\n claimed_by: {\n type: [\"string\", \"null\"],\n description: \"Filter by claim. null = unclaimed.\",\n },\n },\n },\n sort: {\n type: \"string\",\n enum: [\"readiness\", \"depth\", \"recent\", \"created\"],\n },\n limit: { type: \"number\", description: \"Max results (default 20, max 100)\" },\n cursor: { type: \"string\", description: \"Pagination cursor\" },\n },\n required: [\"project\"],\n },\n },\n {\n name: \"graph_restructure\",\n description:\n \"Modify graph structure: move (reparent), merge (combine two nodes), drop (resolve node + subtree with reason), delete (permanently remove node + subtree). Atomic. Reports newly_actionable nodes.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n operations: {\n type: \"array\",\n items: {\n type: \"object\",\n properties: {\n op: {\n type: \"string\",\n enum: [\"move\", \"merge\", \"drop\", \"delete\"],\n },\n node_id: { type: \"string\", description: \"For move and drop\" },\n new_parent: { type: \"string\", description: \"For move\" },\n source: { type: \"string\", description: \"For merge: node to absorb\" },\n target: {\n type: \"string\",\n description: \"For merge: node that survives\",\n },\n reason: { type: \"string\", description: \"For drop: why\" },\n },\n required: [\"op\"],\n },\n },\n },\n required: [\"operations\"],\n },\n },\n {\n name: \"graph_history\",\n description:\n \"Read the audit trail for a node. Shows who changed what, when, and why. Useful for understanding past decisions across sessions.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n node_id: { type: \"string\" },\n limit: { type: \"number\", description: \"Max events (default 20)\" },\n cursor: { type: \"string\", description: \"Pagination cursor\" },\n },\n required: [\"node_id\"],\n },\n },\n {\n name: \"graph_onboard\",\n description:\n \"Single-call orientation for new agents joining a project. Returns project summary, tree structure (depth 2), recent evidence from resolved nodes (knowledge transfer), all context links, and actionable tasks. Use this as your first call when starting work on an existing project.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: { type: \"string\", description: \"Project name (e.g. 'my-project'). Omit to auto-select (works when there's exactly one project).\" },\n evidence_limit: {\n type: \"number\",\n description: \"Max evidence entries to return (default 20, max 50)\",\n },\n },\n },\n },\n {\n name: \"graph_tree\",\n description:\n \"Full tree visualization for a project. Returns the complete task hierarchy with resolve status. Use when you need to see the whole project structure beyond graph_context's single-node neighborhood.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: { type: \"string\", description: \"Project name (e.g. 'my-project')\" },\n depth: {\n type: \"number\",\n description: \"Max tree depth to return (default 10, max 20)\",\n },\n },\n required: [\"project\"],\n },\n },\n {\n name: \"graph_agent_config\",\n description:\n \"Returns the graph-optimized agent configuration file for Claude Code. Save the returned content to .claude/agents/graph.md to enable the graph workflow agent.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {},\n },\n },\n {\n name: \"graph_knowledge_write\",\n description:\n \"Write a knowledge entry for a project. Creates or overwrites a named document. Use for persistent project-level knowledge (architecture decisions, conventions, API contracts) that outlives individual tasks.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: { type: \"string\", description: \"Project name\" },\n key: { type: \"string\", description: \"Knowledge entry key (e.g. 'auth', 'database-schema', 'api-contracts')\" },\n content: { type: \"string\", description: \"Free-form text content\" },\n },\n required: [\"project\", \"key\", \"content\"],\n },\n },\n {\n name: \"graph_knowledge_read\",\n description:\n \"Read knowledge entries for a project. Provide a key to read one entry, or omit to list all entries.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: { type: \"string\", description: \"Project name\" },\n key: { type: \"string\", description: \"Knowledge entry key. Omit to list all.\" },\n },\n required: [\"project\"],\n },\n },\n {\n name: \"graph_knowledge_delete\",\n description:\n \"Delete a knowledge entry from a project.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: { type: \"string\", description: \"Project name\" },\n key: { type: \"string\", description: \"Knowledge entry key to delete\" },\n },\n required: [\"project\", \"key\"],\n },\n },\n {\n name: \"graph_knowledge_search\",\n description:\n \"Search knowledge entries by substring match on key or content.\",\n inputSchema: {\n type: \"object\" as const,\n properties: {\n project: { type: \"string\", description: \"Project name\" },\n query: { type: \"string\", description: \"Search string\" },\n },\n required: [\"project\", \"query\"],\n },\n },\n];\n\nexport async function startServer(): Promise<void> {\n // Set database path — db is created lazily on first tool call\n setDbPath(DB_PATH);\n\n // [sl:N0IDVJQIhENQFsov6-Lhg] Resolve license tier once at startup (reads license file, doesn't touch db)\n const tier: Tier = getLicenseTier(DB_PATH);\n\n const server = new Server(\n { name: \"graph\", version: PKG_VERSION },\n { capabilities: { tools: {}, resources: {} } }\n );\n\n // Fire-and-forget version check (opt-in: GRAPH_UPDATE_CHECK=1)\n if (process.env.GRAPH_UPDATE_CHECK === \"1\") {\n checkForUpdate();\n }\n\n // List tools\n server.setRequestHandler(ListToolsRequestSchema, async () => ({\n tools: TOOLS,\n }));\n\n // Handle tool calls\n server.setRequestHandler(CallToolRequestSchema, async (request) => {\n const { name, arguments: args } = request.params;\n\n try {\n let result: unknown;\n\n switch (name) {\n case \"graph_open\": {\n const openArgs = args as any;\n // Gate: check project limit when creating a new project\n if (openArgs?.project) {\n const { getProjectRoot } = await import(\"./nodes.js\");\n if (!getProjectRoot(openArgs.project)) {\n checkProjectLimit(tier);\n }\n }\n result = handleOpen(openArgs, AGENT_IDENTITY);\n break;\n }\n\n case \"graph_plan\": {\n const planArgs = args as any;\n // Gate: check node limit before creating nodes\n if (planArgs?.nodes?.length > 0) {\n // Determine project from the first node's parent\n const { getNode } = await import(\"./nodes.js\");\n const firstParent = planArgs.nodes[0]?.parent_ref;\n if (firstParent && typeof firstParent === \"string\" && !planArgs.nodes.some((n: any) => n.ref === firstParent)) {\n const parentNode = getNode(firstParent);\n if (parentNode) {\n checkNodeLimit(tier, parentNode.project, planArgs.nodes.length);\n }\n }\n }\n result = handlePlan(planArgs, AGENT_IDENTITY);\n break;\n }\n\n case \"graph_next\": {\n const nextArgs = args as any;\n // Gate: strip scope on free tier\n if (nextArgs?.scope) {\n nextArgs.scope = checkScope(tier, nextArgs.scope);\n }\n result = handleNext(nextArgs, AGENT_IDENTITY, CLAIM_TTL);\n break;\n }\n\n case \"graph_context\":\n result = handleContext(args as any);\n break;\n\n case \"graph_update\":\n result = handleUpdate(args as any, AGENT_IDENTITY);\n break;\n\n case \"graph_connect\":\n result = handleConnect(args as any, AGENT_IDENTITY);\n break;\n\n case \"graph_query\":\n result = handleQuery(args as any);\n break;\n\n case \"graph_restructure\":\n result = handleRestructure(args as any, AGENT_IDENTITY);\n break;\n\n case \"graph_history\":\n result = handleHistory(args as any);\n break;\n\n case \"graph_onboard\": {\n const onboardArgs = args as any;\n // Gate: cap evidence limit on free tier\n onboardArgs.evidence_limit = capEvidenceLimit(tier, onboardArgs?.evidence_limit);\n result = handleOnboard(onboardArgs);\n break;\n }\n\n case \"graph_tree\":\n result = handleTree(args as any);\n break;\n\n case \"graph_agent_config\":\n result = handleAgentConfig(PKG_VERSION);\n break;\n\n case \"graph_knowledge_write\":\n checkKnowledgeTier(tier);\n result = handleKnowledgeWrite(args as any, AGENT_IDENTITY);\n break;\n\n case \"graph_knowledge_read\":\n checkKnowledgeTier(tier);\n result = handleKnowledgeRead(args as any);\n break;\n\n case \"graph_knowledge_delete\":\n checkKnowledgeTier(tier);\n result = handleKnowledgeDelete(args as any);\n break;\n\n case \"graph_knowledge_search\":\n checkKnowledgeTier(tier);\n result = handleKnowledgeSearch(args as any);\n break;\n\n default:\n return {\n content: [\n { type: \"text\" as const, text: JSON.stringify({ error: `Unknown tool: ${name}` }) },\n ],\n isError: true,\n };\n }\n\n const content: Array<{ type: \"text\"; text: string }> = [\n { type: \"text\" as const, text: JSON.stringify(result, null, 2) },\n ];\n if (versionBanner) {\n const agentNote = checkAndUpdateAgentFile();\n const bannerParts = [versionBanner];\n if (agentNote) bannerParts.push(agentNote);\n if (updateWarning) bannerParts.push(updateWarning);\n content.push({ type: \"text\" as const, text: bannerParts.join(\"\\n\") });\n versionBanner = null;\n updateWarning = null;\n }\n return { content };\n } catch (error) {\n const message =\n error instanceof Error ? error.message : String(error);\n const code =\n error instanceof ValidationError\n ? \"validation_error\"\n : error instanceof EngineError\n ? (error as EngineError).code\n : \"error\";\n return {\n content: [\n {\n type: \"text\" as const,\n text: JSON.stringify({ error: message, code }),\n },\n ],\n isError: true,\n };\n }\n });\n\n // [sl:Ps3gCuzhMoQWK6tynsGA4] MCP resources — browsable read-only views of graph data\n\n // Resource templates (dynamic, parameterized URIs)\n server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({\n resourceTemplates: [\n {\n uriTemplate: \"graph://{project}/tree\",\n name: \"Project Tree\",\n description: \"Full task tree for a project with resolve status\",\n mimeType: \"application/json\",\n },\n {\n uriTemplate: \"graph://{project}/knowledge\",\n name: \"Project Knowledge\",\n description: \"All knowledge entries for a project\",\n mimeType: \"application/json\",\n },\n {\n uriTemplate: \"graph://{project}/knowledge/{key}\",\n name: \"Knowledge Entry\",\n description: \"A specific knowledge entry\",\n mimeType: \"application/json\",\n },\n ],\n }));\n\n // Static resource list (enumerate known projects)\n server.setRequestHandler(ListResourcesRequestSchema, async () => {\n try {\n const { listProjects } = await import(\"./nodes.js\");\n const projects = listProjects();\n const resources = projects.flatMap((p) => [\n {\n uri: `graph://${p.project}/tree`,\n name: `${p.project} — Tree`,\n description: `Task tree: ${p.total} nodes (${p.resolved} resolved)`,\n mimeType: \"application/json\",\n },\n {\n uri: `graph://${p.project}/knowledge`,\n name: `${p.project} — Knowledge`,\n description: `Knowledge entries for ${p.project}`,\n mimeType: \"application/json\",\n },\n ]);\n return { resources };\n } catch {\n return { resources: [] };\n }\n });\n\n // Read a specific resource\n server.setRequestHandler(ReadResourceRequestSchema, async (request) => {\n const uri = request.params.uri;\n const match = uri.match(/^graph:\\/\\/([^/]+)\\/(.+)$/);\n if (!match) {\n throw new Error(`Invalid resource URI: ${uri}`);\n }\n\n const [, project, path] = match;\n\n if (path === \"tree\") {\n const result = handleTree({ project });\n return {\n contents: [{ uri, mimeType: \"application/json\", text: JSON.stringify(result, null, 2) }],\n };\n }\n\n if (path === \"knowledge\") {\n const result = handleKnowledgeRead({ project });\n return {\n contents: [{ uri, mimeType: \"application/json\", text: JSON.stringify(result, null, 2) }],\n };\n }\n\n const knowledgeMatch = path.match(/^knowledge\\/(.+)$/);\n if (knowledgeMatch) {\n const result = handleKnowledgeRead({ project, key: knowledgeMatch[1] });\n return {\n contents: [{ uri, mimeType: \"application/json\", text: JSON.stringify(result, null, 2) }],\n };\n }\n\n throw new Error(`Unknown resource path: ${path}`);\n });\n\n // Connect transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n // Periodic WAL checkpoint every 30s — flushes WAL data into main db file\n const checkpointInterval = setInterval(() => {\n try { checkpointDb(); } catch {}\n }, 30_000);\n\n // Cleanup on exit\n process.on(\"SIGINT\", () => {\n clearInterval(checkpointInterval);\n closeDb();\n process.exit(0);\n });\n process.on(\"SIGTERM\", () => {\n clearInterval(checkpointInterval);\n closeDb();\n process.exit(0);\n });\n}\n","import { createNode, getProjectRoot, listProjects, getProjectSummary } from \"../nodes.js\";\nimport { optionalString } from \"../validate.js\";\nimport type { Node } from \"../types.js\";\n\nexport interface OpenInput {\n project?: string;\n goal?: string;\n skip_discovery?: boolean;\n}\n\nexport type OpenResult =\n | {\n projects: Array<{\n project: string;\n id: string;\n summary: string;\n total: number;\n resolved: number;\n unresolved: number;\n updated_at: string;\n }>;\n }\n | {\n project: string;\n root: Node;\n summary: {\n total: number;\n resolved: number;\n unresolved: number;\n blocked: number;\n actionable: number;\n };\n hint?: string;\n };\n\nexport function handleOpen(input: OpenInput, agent: string): OpenResult {\n const project = optionalString(input?.project, \"project\");\n const goal = optionalString(input?.goal, \"goal\");\n\n if (!project) {\n return { projects: listProjects() };\n }\n\n let root = getProjectRoot(project);\n let isNew = false;\n\n if (!root) {\n root = createNode({\n project,\n summary: goal ?? project,\n discovery: input?.skip_discovery ? \"done\" : \"pending\",\n agent,\n });\n isNew = true;\n }\n\n const summary = getProjectSummary(project);\n\n const result: OpenResult = { project, root, summary };\n\n // Guide the agent on what to do next\n if (isNew && root.discovery === \"pending\") {\n result.hint = `New project created. Discovery is pending — interview the user to understand scope and goals, then set discovery to \"done\" via graph_update before decomposing with graph_plan.`;\n } else if (isNew) {\n result.hint = `New project created. Ready to decompose — use graph_plan to add tasks.`;\n } else if (root.discovery === \"pending\") {\n result.hint = `Discovery is still pending on this project. Complete the discovery interview, then set discovery to \"done\" via graph_update.`;\n } else if (summary.actionable > 0) {\n result.hint = `${summary.actionable} actionable task(s). Use graph_next to claim one.`;\n } else if (summary.unresolved > 0 && summary.actionable === 0) {\n result.hint = `All remaining tasks are blocked. Check dependencies with graph_query.`;\n }\n\n return result;\n}\n","import { nanoid } from \"nanoid\";\nimport { getDb } from \"./db.js\";\nimport { logEvent } from \"./events.js\";\nimport type { Edge } from \"./types.js\";\n\n// --- Cycle detection ---\n\nfunction wouldCreateCycle(from: string, to: string): boolean {\n // Adding edge \"from depends_on to\". Check if to can already reach from\n // through existing depends_on edges. If so, adding this edge creates a cycle.\n const db = getDb();\n const visited = new Set<string>();\n const stack = [to];\n\n while (stack.length > 0) {\n const current = stack.pop()!;\n if (current === from) return true;\n if (visited.has(current)) continue;\n visited.add(current);\n\n // Follow forward depends_on edges: what does current depend on?\n const deps = db\n .prepare(\n `SELECT to_node FROM edges WHERE from_node = ? AND type = 'depends_on'`\n )\n .all(current) as Array<{ to_node: string }>;\n\n for (const dep of deps) {\n stack.push(dep.to_node);\n }\n }\n\n return false;\n}\n\n// --- Add edge ---\n\nexport interface AddEdgeInput {\n from: string;\n to: string;\n type: string;\n agent: string;\n}\n\nexport interface AddEdgeResult {\n edge: Edge | null;\n rejected: boolean;\n reason?: string;\n}\n\nexport function addEdge(input: AddEdgeInput): AddEdgeResult {\n const db = getDb();\n\n // Check nodes exist\n const fromExists = db.prepare(\"SELECT id FROM nodes WHERE id = ?\").get(input.from);\n const toExists = db.prepare(\"SELECT id FROM nodes WHERE id = ?\").get(input.to);\n\n if (!fromExists) {\n return { edge: null, rejected: true, reason: \"node_not_found: \" + input.from };\n }\n if (!toExists) {\n return { edge: null, rejected: true, reason: \"node_not_found: \" + input.to };\n }\n\n // Check for duplicates\n const existing = db\n .prepare(\n \"SELECT id FROM edges WHERE from_node = ? AND to_node = ? AND type = ?\"\n )\n .get(input.from, input.to, input.type);\n\n if (existing) {\n return { edge: null, rejected: true, reason: \"duplicate_edge\" };\n }\n\n // Cycle detection for depends_on\n if (input.type === \"depends_on\") {\n if (wouldCreateCycle(input.from, input.to)) {\n return { edge: null, rejected: true, reason: \"cycle_detected\" };\n }\n }\n\n const edge: Edge = {\n id: nanoid(),\n from_node: input.from,\n to_node: input.to,\n type: input.type,\n created_at: new Date().toISOString(),\n };\n\n db.prepare(`\n INSERT INTO edges (id, from_node, to_node, type, created_at)\n VALUES (?, ?, ?, ?, ?)\n `).run(edge.id, edge.from_node, edge.to_node, edge.type, edge.created_at);\n\n logEvent(input.from, input.agent, \"edge_added\", [\n { field: \"edge\", before: null, after: { to: input.to, type: input.type } },\n ]);\n\n return { edge, rejected: false };\n}\n\n// --- Remove edge ---\n\nexport function removeEdge(\n from: string,\n to: string,\n type: string,\n agent: string\n): boolean {\n const db = getDb();\n\n const result = db\n .prepare(\n \"DELETE FROM edges WHERE from_node = ? AND to_node = ? AND type = ?\"\n )\n .run(from, to, type);\n\n if (result.changes > 0) {\n logEvent(from, agent, \"edge_removed\", [\n { field: \"edge\", before: { to, type }, after: null },\n ]);\n return true;\n }\n\n return false;\n}\n\n// --- Query edges ---\n\nexport function getEdgesFrom(nodeId: string, type?: string): Edge[] {\n const db = getDb();\n\n if (type) {\n return db\n .prepare(\"SELECT * FROM edges WHERE from_node = ? AND type = ?\")\n .all(nodeId, type) as Edge[];\n }\n\n return db\n .prepare(\"SELECT * FROM edges WHERE from_node = ?\")\n .all(nodeId) as Edge[];\n}\n\nexport function getEdgesTo(nodeId: string, type?: string): Edge[] {\n const db = getDb();\n\n if (type) {\n return db\n .prepare(\"SELECT * FROM edges WHERE to_node = ? AND type = ?\")\n .all(nodeId, type) as Edge[];\n }\n\n return db\n .prepare(\"SELECT * FROM edges WHERE to_node = ?\")\n .all(nodeId) as Edge[];\n}\n\n// [sl:uRocbNC_bArUXGr908Qbk] Find newly actionable nodes\n// Targeted: accepts resolved node IDs, checks only direct dependents.\n// Falls back to project-wide scan when no IDs provided.\n\nexport function findNewlyActionable(\n project: string,\n resolvedNodeIds?: string[]\n): Array<{ id: string; summary: string }> {\n const db = getDb();\n\n if (resolvedNodeIds && resolvedNodeIds.length > 0) {\n // Targeted: only check direct dependents of the resolved nodes + children of resolved nodes\n const placeholders = resolvedNodeIds.map(() => \"?\").join(\",\");\n const rows = db\n .prepare(\n `SELECT DISTINCT n.id, n.summary FROM nodes n\n WHERE n.resolved = 0 AND n.project = ?\n AND (\n -- nodes that had a depends_on edge to one of the resolved nodes\n n.id IN (\n SELECT e.from_node FROM edges e\n WHERE e.type = 'depends_on' AND e.to_node IN (${placeholders})\n )\n OR\n -- parents of resolved nodes (might now be leaf if all children resolved)\n n.id IN (SELECT parent FROM nodes WHERE id IN (${placeholders}) AND parent IS NOT NULL)\n )\n -- is a leaf (no unresolved children)\n AND NOT EXISTS (\n SELECT 1 FROM nodes child WHERE child.parent = n.id AND child.resolved = 0\n )\n -- all deps resolved\n AND NOT EXISTS (\n SELECT 1 FROM edges e\n JOIN nodes dep ON dep.id = e.to_node AND dep.resolved = 0\n WHERE e.from_node = n.id AND e.type = 'depends_on'\n )`\n )\n .all(project, ...resolvedNodeIds, ...resolvedNodeIds) as Array<{\n id: string;\n summary: string;\n }>;\n\n return rows;\n }\n\n // Fallback: project-wide scan\n const rows = db\n .prepare(\n `SELECT n.id, n.summary FROM nodes n\n WHERE n.project = ? AND n.resolved = 0\n AND NOT EXISTS (\n SELECT 1 FROM nodes child WHERE child.parent = n.id AND child.resolved = 0\n )\n AND NOT EXISTS (\n SELECT 1 FROM edges e\n JOIN nodes dep ON dep.id = e.to_node AND dep.resolved = 0\n WHERE e.from_node = n.id AND e.type = 'depends_on'\n )`\n )\n .all(project) as Array<{ id: string; summary: string }>;\n\n return rows;\n}\n","import { getDb } from \"../db.js\";\nimport { createNode, getNode } from \"../nodes.js\";\nimport { addEdge } from \"../edges.js\";\nimport { requireArray, requireString, EngineError } from \"../validate.js\";\n\nexport interface PlanNodeInput {\n ref: string;\n parent_ref?: string;\n summary: string;\n context_links?: string[];\n depends_on?: string[];\n properties?: Record<string, unknown>;\n}\n\nexport interface PlanInput {\n nodes: PlanNodeInput[];\n}\n\nexport interface PlanResult {\n created: Array<{ ref: string; id: string }>;\n}\n\nexport function handlePlan(input: PlanInput, agent: string): PlanResult {\n const db = getDb();\n const nodes = requireArray<PlanNodeInput>(input?.nodes, \"nodes\");\n\n // Validate each node has required fields\n for (let i = 0; i < nodes.length; i++) {\n const n = nodes[i];\n requireString(n.ref, `nodes[${i}].ref`);\n requireString(n.summary, `nodes[${i}].summary`);\n }\n\n // Ref -> real ID mapping\n const refMap = new Map<string, string>();\n const created: Array<{ ref: string; id: string }> = [];\n\n // Validate refs are unique\n const refs = new Set<string>();\n for (const node of nodes) {\n if (refs.has(node.ref)) {\n throw new EngineError(\"duplicate_ref\", `Duplicate ref in batch: ${node.ref}`);\n }\n refs.add(node.ref);\n }\n\n // Run atomically\n const transaction = db.transaction(() => {\n // First pass: create all nodes\n for (const nodeInput of nodes) {\n // Resolve parent\n let parentId: string | undefined;\n if (nodeInput.parent_ref) {\n // Check if it's a batch ref or existing node ID\n parentId = refMap.get(nodeInput.parent_ref);\n if (!parentId) {\n // Try as existing node ID\n const existing = getNode(nodeInput.parent_ref);\n if (existing) {\n parentId = existing.id;\n } else {\n throw new EngineError(\n \"invalid_parent_ref\",\n `parent_ref \"${nodeInput.parent_ref}\" is neither a batch ref nor an existing node ID`\n );\n }\n }\n }\n\n // Determine project from parent or require first node to have a parent\n let project: string;\n if (parentId) {\n const parentNode = getNode(parentId)!;\n // [sl:m3_UNy-eICtHeHExfHwUH] Block decomposition when node has pending discovery\n if (parentNode.discovery === \"pending\") {\n throw new EngineError(\n \"discovery_pending\",\n `Cannot add children to \"${parentNode.summary}\" (${parentId}) — discovery is pending. Run: graph_update({ updates: [{ node_id: \"${parentId}\", discovery: \"done\" }] }) after completing discovery, then decompose.`\n );\n }\n project = parentNode.project;\n } else {\n // If no parent, the node must be a root. But we need a project.\n // Infer from first node that has a parent, or error.\n throw new EngineError(\n \"missing_parent\",\n `Node \"${nodeInput.ref}\" has no parent_ref. All planned nodes must have a parent (an existing node or a batch ref).`\n );\n }\n\n const node = createNode({\n project,\n parent: parentId,\n summary: nodeInput.summary,\n context_links: nodeInput.context_links,\n properties: nodeInput.properties,\n agent,\n });\n\n refMap.set(nodeInput.ref, node.id);\n created.push({ ref: nodeInput.ref, id: node.id });\n }\n\n // Second pass: create dependency edges\n for (const nodeInput of nodes) {\n if (!nodeInput.depends_on || nodeInput.depends_on.length === 0) continue;\n\n const fromId = refMap.get(nodeInput.ref)!;\n\n for (const dep of nodeInput.depends_on) {\n // Resolve dep: batch ref or existing node ID\n let toId = refMap.get(dep);\n if (!toId) {\n const existing = getNode(dep);\n if (existing) {\n toId = existing.id;\n } else {\n throw new EngineError(\n \"invalid_depends_on\",\n `depends_on \"${dep}\" in node \"${nodeInput.ref}\" is neither a batch ref nor an existing node ID`\n );\n }\n }\n\n const result = addEdge({\n from: fromId,\n to: toId,\n type: \"depends_on\",\n agent,\n });\n\n if (result.rejected) {\n throw new EngineError(\n \"edge_rejected\",\n `Dependency edge from \"${nodeInput.ref}\" to \"${dep}\" rejected: ${result.reason}`\n );\n }\n }\n }\n });\n\n transaction();\n\n return { created };\n}\n","import { updateNode, getNode, getNodeOrThrow, getChildren } from \"../nodes.js\";\nimport { findNewlyActionable } from \"../edges.js\";\nimport { requireArray, requireString, EngineError } from \"../validate.js\";\n\nexport interface UpdateEntry {\n node_id: string;\n expected_rev?: number;\n resolved?: boolean;\n resolved_reason?: string; // [sl:QBEtldx8PBWACftEM8MYl] Shorthand — auto-creates note evidence\n discovery?: string | null;\n blocked?: boolean;\n blocked_reason?: string | null;\n state?: unknown;\n summary?: string;\n properties?: Record<string, unknown>;\n add_context_links?: string[];\n remove_context_links?: string[];\n add_evidence?: Array<{ type: string; ref: string }>;\n}\n\nexport interface UpdateInput {\n updates: UpdateEntry[];\n}\n\nexport interface UpdateResult {\n updated: Array<{ node_id: string; rev: number }>;\n newly_actionable?: Array<{ id: string; summary: string }>;\n auto_resolved?: Array<{ node_id: string; summary: string }>;\n}\n\nexport function handleUpdate(input: UpdateInput, agent: string): UpdateResult {\n const updates = requireArray<UpdateEntry>(input?.updates, \"updates\");\n\n for (let i = 0; i < updates.length; i++) {\n requireString(updates[i].node_id, `updates[${i}].node_id`);\n if (updates[i].add_evidence) {\n for (let j = 0; j < updates[i].add_evidence!.length; j++) {\n requireString(updates[i].add_evidence![j].type, `updates[${i}].add_evidence[${j}].type`);\n requireString(updates[i].add_evidence![j].ref, `updates[${i}].add_evidence[${j}].ref`);\n }\n }\n }\n\n const updated: Array<{ node_id: string; rev: number }> = [];\n const resolvedIds: string[] = [];\n const resolvedProjects = new Set<string>();\n\n for (const entry of updates) {\n // Optimistic concurrency: reject if rev doesn't match\n if (entry.expected_rev !== undefined) {\n const current = getNodeOrThrow(entry.node_id);\n if (current.rev !== entry.expected_rev) {\n throw new EngineError(\n \"rev_mismatch\",\n `Node ${entry.node_id} has rev ${current.rev}, expected ${entry.expected_rev}. Another agent may have modified it. Re-read and retry.`\n );\n }\n }\n\n // Expand resolved_reason shorthand into evidence\n let evidence = entry.add_evidence;\n if (entry.resolved_reason) {\n evidence = [...(evidence ?? []), { type: \"note\", ref: entry.resolved_reason }];\n }\n\n const node = updateNode({\n node_id: entry.node_id,\n agent,\n resolved: entry.resolved,\n discovery: entry.discovery,\n blocked: entry.blocked,\n blocked_reason: entry.blocked_reason,\n state: entry.state,\n summary: entry.summary,\n properties: entry.properties,\n add_context_links: entry.add_context_links,\n remove_context_links: entry.remove_context_links,\n add_evidence: evidence,\n });\n\n updated.push({ node_id: node.id, rev: node.rev });\n\n if (entry.resolved === true) {\n resolvedIds.push(node.id);\n resolvedProjects.add(node.project);\n }\n }\n\n // [sl:GBuFbmTFuFfnl5KWW-ja-] Auto-resolve parents when all children are resolved\n const autoResolved: Array<{ node_id: string; summary: string }> = [];\n if (resolvedIds.length > 0) {\n const seen = new Set<string>(resolvedIds);\n const queue = [...resolvedIds];\n\n while (queue.length > 0) {\n const nodeId = queue.shift()!;\n const node = getNode(nodeId);\n if (!node?.parent) continue;\n\n const parentId = node.parent;\n if (seen.has(parentId)) continue;\n seen.add(parentId);\n\n const parent = getNode(parentId);\n if (!parent || parent.resolved) continue;\n\n const children = getChildren(parentId);\n if (children.length === 0) continue;\n if (children.every((c) => c.resolved)) {\n const resolved = updateNode({\n node_id: parentId,\n agent,\n resolved: true,\n add_evidence: [{ type: \"note\", ref: \"Auto-resolved: all children completed\" }],\n });\n updated.push({ node_id: resolved.id, rev: resolved.rev });\n resolvedIds.push(parentId);\n autoResolved.push({ node_id: parentId, summary: parent.summary });\n queue.push(parentId);\n }\n }\n }\n\n const result: UpdateResult = { updated };\n\n if (resolvedIds.length > 0 && resolvedProjects.size > 0) {\n const allActionable: Array<{ id: string; summary: string }> = [];\n for (const proj of resolvedProjects) {\n allActionable.push(...findNewlyActionable(proj, resolvedIds));\n }\n result.newly_actionable = allActionable;\n }\n\n if (autoResolved.length > 0) {\n result.auto_resolved = autoResolved;\n }\n\n return result;\n}\n","import { addEdge, removeEdge } from \"../edges.js\";\nimport { requireArray, requireString } from \"../validate.js\";\n\nexport interface ConnectEdgeInput {\n from: string;\n to: string;\n type: string;\n remove?: boolean;\n}\n\nexport interface ConnectInput {\n edges: ConnectEdgeInput[];\n}\n\nexport interface ConnectResult {\n applied: number;\n rejected?: Array<{ from: string; to: string; reason: string }>;\n}\n\nexport function handleConnect(input: ConnectInput, agent: string): ConnectResult {\n const edges = requireArray<ConnectEdgeInput>(input?.edges, \"edges\");\n\n for (let i = 0; i < edges.length; i++) {\n requireString(edges[i].from, `edges[${i}].from`);\n requireString(edges[i].to, `edges[${i}].to`);\n requireString(edges[i].type, `edges[${i}].type`);\n }\n\n let applied = 0;\n const rejected: Array<{ from: string; to: string; reason: string }> = [];\n\n for (const edge of edges) {\n if (edge.type === \"parent\") {\n rejected.push({\n from: edge.from,\n to: edge.to,\n reason: \"parent_edges_not_allowed: use graph_restructure to reparent\",\n });\n continue;\n }\n\n if (edge.remove) {\n const removed = removeEdge(edge.from, edge.to, edge.type, agent);\n if (removed) {\n applied++;\n } else {\n rejected.push({\n from: edge.from,\n to: edge.to,\n reason: \"edge_not_found\",\n });\n }\n } else {\n const result = addEdge({\n from: edge.from,\n to: edge.to,\n type: edge.type,\n agent,\n });\n\n if (result.rejected) {\n rejected.push({\n from: edge.from,\n to: edge.to,\n reason: result.reason!,\n });\n } else {\n applied++;\n }\n }\n }\n\n const result: ConnectResult = { applied };\n if (rejected.length > 0) {\n result.rejected = rejected;\n }\n return result;\n}\n","import { getNodeOrThrow, getChildren, getAncestors, getSubtreeProgress } from \"../nodes.js\";\nimport { getEdgesFrom, getEdgesTo } from \"../edges.js\";\nimport { getNode } from \"../nodes.js\";\nimport { requireString, optionalNumber } from \"../validate.js\";\nimport type { Node } from \"../types.js\";\n\nexport interface ContextInput {\n node_id: string;\n depth?: number;\n}\n\ninterface NodeTree {\n id: string;\n summary: string;\n resolved: boolean;\n discovery: string | null;\n state: unknown;\n progress?: { resolved: number; total: number };\n children?: NodeTree[];\n child_count?: number;\n}\n\nexport interface ContextResult {\n node: Node;\n ancestors: Array<{ id: string; summary: string; resolved: boolean }>;\n children: NodeTree;\n depends_on: Array<{ node: Node; satisfied: boolean }>;\n depended_by: Array<{ node: Node; satisfied: boolean }>;\n}\n\nfunction buildNodeTree(nodeId: string, currentDepth: number, maxDepth: number): NodeTree {\n const node = getNodeOrThrow(nodeId);\n const children = getChildren(nodeId);\n\n const tree: NodeTree = {\n id: node.id,\n summary: node.summary,\n resolved: node.resolved,\n discovery: node.discovery,\n state: node.state,\n };\n\n if (children.length === 0) {\n return tree;\n }\n\n tree.progress = getSubtreeProgress(nodeId);\n\n if (currentDepth < maxDepth) {\n tree.children = children.map((child) =>\n buildNodeTree(child.id, currentDepth + 1, maxDepth)\n );\n } else {\n tree.child_count = children.length;\n }\n\n return tree;\n}\n\nexport function handleContext(input: ContextInput): ContextResult {\n const nodeId = requireString(input?.node_id, \"node_id\");\n const depth = optionalNumber(input?.depth, \"depth\", 0, 10) ?? 2;\n const node = getNodeOrThrow(nodeId);\n const ancestors = getAncestors(nodeId);\n\n // Build children tree\n const children = buildNodeTree(nodeId, 0, depth);\n\n // Get dependency edges\n const depsOut = getEdgesFrom(nodeId, \"depends_on\");\n const depsIn = getEdgesTo(nodeId, \"depends_on\");\n\n const depends_on = depsOut.map((edge) => {\n const target = getNode(edge.to_node);\n return {\n node: target!,\n satisfied: target?.resolved ?? false,\n };\n });\n\n const depended_by = depsIn.map((edge) => {\n const source = getNode(edge.from_node);\n return {\n node: source!,\n satisfied: node.resolved,\n };\n });\n\n return { node, ancestors, children, depends_on, depended_by };\n}\n","import { getDb } from \"../db.js\";\nimport { requireString, optionalNumber, optionalString } from \"../validate.js\";\nimport type { NodeRow } from \"../types.js\";\n\nexport interface QueryFilter {\n resolved?: boolean;\n properties?: Record<string, unknown>;\n text?: string;\n ancestor?: string;\n has_evidence_type?: string;\n is_leaf?: boolean;\n is_actionable?: boolean;\n is_blocked?: boolean;\n claimed_by?: string | null;\n}\n\nexport interface QueryInput {\n project: string;\n filter?: QueryFilter;\n sort?: \"readiness\" | \"depth\" | \"recent\" | \"created\";\n limit?: number;\n cursor?: string;\n}\n\nexport interface QueryResultNode {\n id: string;\n summary: string;\n resolved: boolean;\n state: unknown;\n parent: string | null;\n depth: number;\n properties: Record<string, unknown>;\n}\n\nexport interface QueryResult {\n nodes: QueryResultNode[];\n total: number;\n next_cursor?: string;\n}\n\n// [sl:tfMDHhmJSXd5TPgwD2ZC6] Descendant lookup via recursive CTE (replaced JS BFS)\nfunction getDescendantIds(nodeId: string): string[] {\n const db = getDb();\n const rows = db\n .prepare(\n `WITH RECURSIVE descendants(id) AS (\n SELECT id FROM nodes WHERE parent = ?\n UNION ALL\n SELECT n.id FROM nodes n JOIN descendants d ON n.parent = d.id\n )\n SELECT id FROM descendants`\n )\n .all(nodeId) as Array<{ id: string }>;\n\n return rows.map((r) => r.id);\n}\n\n\nexport function handleQuery(input: QueryInput): QueryResult {\n const project = requireString(input?.project, \"project\");\n const db = getDb();\n const limit = Math.min(optionalNumber(input?.limit, \"limit\", 1, 100) ?? 20, 100);\n const filter = input?.filter;\n const cursor = optionalString(input?.cursor, \"cursor\");\n\n // Build WHERE clauses\n const conditions: string[] = [\"n.project = ?\"];\n const params: unknown[] = [project];\n\n if (filter?.resolved !== undefined) {\n conditions.push(\"n.resolved = ?\");\n params.push(filter.resolved ? 1 : 0);\n }\n\n if (filter?.text) {\n conditions.push(\"n.summary LIKE ?\");\n params.push(`%${filter.text}%`);\n }\n\n if (filter?.ancestor) {\n const descendantIds = getDescendantIds(filter.ancestor);\n if (descendantIds.length === 0) {\n return { nodes: [], total: 0 };\n }\n conditions.push(`n.id IN (${descendantIds.map(() => \"?\").join(\",\")})`);\n params.push(...descendantIds);\n }\n\n if (filter?.has_evidence_type) {\n conditions.push(\n `EXISTS (SELECT 1 FROM json_each(n.evidence) WHERE json_extract(value, '$.type') = ?)`\n );\n params.push(filter.has_evidence_type);\n }\n\n if (filter?.is_leaf) {\n conditions.push(\n \"NOT EXISTS (SELECT 1 FROM nodes child WHERE child.parent = n.id AND child.resolved = 0)\"\n );\n }\n\n if (filter?.is_actionable) {\n conditions.push(\"n.resolved = 0\");\n conditions.push(\"n.blocked = 0\");\n conditions.push(\n \"NOT EXISTS (SELECT 1 FROM nodes child WHERE child.parent = n.id AND child.resolved = 0)\"\n );\n conditions.push(\n `NOT EXISTS (\n SELECT 1 FROM edges e\n JOIN nodes dep ON dep.id = e.to_node AND dep.resolved = 0\n WHERE e.from_node = n.id AND e.type = 'depends_on'\n )`\n );\n }\n\n if (filter?.is_blocked) {\n conditions.push(\"n.resolved = 0\");\n conditions.push(\n `(n.blocked = 1 OR EXISTS (\n SELECT 1 FROM edges e\n JOIN nodes dep ON dep.id = e.to_node AND dep.resolved = 0\n WHERE e.from_node = n.id AND e.type = 'depends_on'\n ))`\n );\n }\n\n if (filter?.properties) {\n for (const [key, value] of Object.entries(filter.properties)) {\n conditions.push(\"json_extract(n.properties, ?) = ?\");\n params.push(`$.${key}`, value as string | number);\n }\n }\n\n if (filter?.claimed_by !== undefined) {\n if (filter.claimed_by === null) {\n conditions.push(\n \"(json_extract(n.properties, '$._claimed_by') IS NULL)\"\n );\n } else {\n conditions.push(\"json_extract(n.properties, '$._claimed_by') = ?\");\n params.push(filter.claimed_by);\n }\n }\n\n // Cursor: use created_at + id for stable pagination\n if (cursor) {\n const [cursorTime, cursorId] = cursor.split(\"|\");\n conditions.push(\"(n.created_at > ? OR (n.created_at = ? AND n.id > ?))\");\n params.push(cursorTime, cursorTime, cursorId);\n }\n\n const whereClause = conditions.join(\" AND \");\n\n // Sorting\n let orderBy: string;\n switch (input.sort) {\n case \"depth\":\n // Can't sort by computed depth in SQL easily, so sort by created and compute depth post-hoc\n orderBy = \"n.created_at ASC, n.id ASC\";\n break;\n case \"recent\":\n orderBy = \"n.updated_at DESC, n.id ASC\";\n break;\n case \"created\":\n orderBy = \"n.created_at ASC, n.id ASC\";\n break;\n case \"readiness\":\n default:\n orderBy = \"n.updated_at ASC, n.id ASC\";\n break;\n }\n\n // Count total\n // Count total (without cursor filter)\n const countConditions = cursor ? conditions.slice(0, -1) : conditions;\n const countParams = cursor ? params.slice(0, -3) : [...params];\n const total = (\n db.prepare(`SELECT COUNT(*) as count FROM nodes n WHERE ${countConditions.join(\" AND \")}`).get(...countParams) as { count: number }\n ).count;\n\n // Fetch\n params.push(limit + 1);\n const query = `SELECT * FROM nodes n WHERE ${whereClause} ORDER BY ${orderBy} LIMIT ?`;\n const rows = db.prepare(query).all(...params) as NodeRow[];\n\n const hasMore = rows.length > limit;\n const slice = hasMore ? rows.slice(0, limit) : rows;\n\n const nodes: QueryResultNode[] = slice.map((row) => ({\n id: row.id,\n summary: row.summary,\n resolved: row.resolved === 1,\n state: row.state ? JSON.parse(row.state) : null,\n parent: row.parent,\n depth: row.depth,\n properties: JSON.parse(row.properties),\n }));\n\n const result: QueryResult = { nodes, total };\n\n if (hasMore) {\n const last = slice[slice.length - 1];\n result.next_cursor = `${last.created_at}|${last.id}`;\n }\n\n return result;\n}\n","import { getDb } from \"../db.js\";\nimport { getNode, getAncestors, updateNode } from \"../nodes.js\";\nimport { getEdgesFrom } from \"../edges.js\";\nimport { requireString, optionalString, optionalNumber, optionalBoolean } from \"../validate.js\";\nimport type { Node, NodeRow, Evidence } from \"../types.js\";\n\nexport interface NextInput {\n project: string;\n scope?: string;\n filter?: Record<string, unknown>;\n count?: number;\n claim?: boolean;\n}\n\nexport interface NextResultNode {\n node: Node;\n ancestors: Array<{ id: string; summary: string }>;\n context_links: {\n self: string[];\n inherited: Array<{ node_id: string; links: string[] }>;\n };\n resolved_deps: Array<{\n id: string;\n summary: string;\n evidence: Evidence[];\n }>;\n}\n\nexport interface ClaimedTask {\n id: string;\n summary: string;\n claimed_at: string;\n}\n\nexport interface NextResult {\n nodes: NextResultNode[];\n your_claims?: ClaimedTask[];\n}\n\nexport function handleNext(\n input: NextInput,\n agent: string,\n claimTtlMinutes: number = 60\n): NextResult {\n const project = requireString(input?.project, \"project\");\n const scope = optionalString(input?.scope, \"scope\");\n const count = optionalNumber(input?.count, \"count\", 1, 50) ?? 1;\n const claim = optionalBoolean(input?.claim, \"claim\") ?? false;\n const db = getDb();\n\n // [sl:HB5daFH1HlFXzuTluibnk] Scope filtering: restrict to descendants of a given node\n let scopeFilter = \"\";\n const scopeParams: unknown[] = [];\n if (scope) {\n const descendantIds = db\n .prepare(\n `WITH RECURSIVE descendants(id) AS (\n SELECT id FROM nodes WHERE parent = ?\n UNION ALL\n SELECT n.id FROM nodes n JOIN descendants d ON n.parent = d.id\n )\n SELECT id FROM descendants`\n )\n .all(scope) as Array<{ id: string }>;\n\n if (descendantIds.length === 0) {\n return { nodes: [] };\n }\n scopeFilter = `AND n.id IN (${descendantIds.map(() => \"?\").join(\",\")})`;\n scopeParams.push(...descendantIds.map((d) => d.id));\n }\n\n // Find actionable nodes: unresolved, not blocked, leaf (no unresolved children), all deps resolved\n let query = `\n SELECT n.* FROM nodes n\n WHERE n.project = ? AND n.resolved = 0 AND n.blocked = 0\n ${scopeFilter}\n AND NOT EXISTS (\n SELECT 1 FROM nodes child WHERE child.parent = n.id AND child.resolved = 0\n )\n AND NOT EXISTS (\n SELECT 1 FROM edges e\n JOIN nodes dep ON dep.id = e.to_node AND dep.resolved = 0\n WHERE e.from_node = n.id AND e.type = 'depends_on'\n )\n `;\n\n const params: unknown[] = [project, ...scopeParams];\n\n // Skip nodes claimed by other agents (if claim TTL hasn't expired)\n const claimCutoff = new Date(\n Date.now() - claimTtlMinutes * 60 * 1000\n ).toISOString();\n\n query += `\n AND (\n json_extract(n.properties, '$._claimed_by') IS NULL\n OR json_extract(n.properties, '$._claimed_by') = ?\n OR json_extract(n.properties, '$._claimed_at') <= ?\n )\n `;\n params.push(agent, claimCutoff);\n\n // Property filters\n if (input.filter) {\n for (const [key, value] of Object.entries(input.filter)) {\n query += \" AND json_extract(n.properties, ?) = ?\";\n params.push(`$.${key}`, value as string | number);\n }\n }\n\n // [sl:md48WyMYFlOf4KP99vmtv] Ranking fully in SQL — never loads more than N rows\n // Depth is cached on the node, priority extracted via json_extract\n query += `\n ORDER BY\n COALESCE(CAST(json_extract(n.properties, '$.priority') AS REAL), 0) DESC,\n n.depth DESC,\n n.updated_at ASC\n LIMIT ?\n `;\n params.push(count);\n\n const rows = db.prepare(query).all(...params) as NodeRow[];\n\n const selected = rows.map((row) => ({ row }));\n\n const results: NextResultNode[] = selected.map(({ row }) => {\n const node = getNode(row.id)!;\n const ancestors = getAncestors(row.id);\n\n // Context links: self + inherited from ancestors\n const inherited: Array<{ node_id: string; links: string[] }> = [];\n for (const anc of ancestors) {\n const ancNode = getNode(anc.id);\n if (ancNode && ancNode.context_links.length > 0) {\n inherited.push({ node_id: anc.id, links: ancNode.context_links });\n }\n }\n\n // Resolved dependencies\n const depEdges = getEdgesFrom(row.id, \"depends_on\");\n const resolved_deps = depEdges\n .map((edge) => {\n const depNode = getNode(edge.to_node);\n if (!depNode || !depNode.resolved) return null;\n return {\n id: depNode.id,\n summary: depNode.summary,\n evidence: depNode.evidence,\n };\n })\n .filter(Boolean) as NextResultNode[\"resolved_deps\"];\n\n // Claim if requested\n if (claim) {\n updateNode({\n node_id: node.id,\n agent,\n properties: {\n _claimed_by: agent,\n _claimed_at: new Date().toISOString(),\n },\n });\n }\n\n return {\n node: claim ? getNode(row.id)! : node,\n ancestors: ancestors.map((a) => ({ id: a.id, summary: a.summary })),\n context_links: {\n self: node.context_links,\n inherited,\n },\n resolved_deps,\n };\n });\n\n // Surface caller's existing claims (unexpired) so they can resume or release them\n const claimRows = db\n .prepare(\n `SELECT id, summary, json_extract(properties, '$._claimed_at') as claimed_at\n FROM nodes\n WHERE project = ? AND resolved = 0\n AND json_extract(properties, '$._claimed_by') = ?\n AND json_extract(properties, '$._claimed_at') > ?\n ORDER BY json_extract(properties, '$._claimed_at') DESC`\n )\n .all(project, agent, claimCutoff) as Array<{ id: string; summary: string; claimed_at: string }>;\n\n const result: NextResult = { nodes: results };\n if (claimRows.length > 0) {\n result.your_claims = claimRows.map((r) => ({\n id: r.id,\n summary: r.summary,\n claimed_at: r.claimed_at,\n }));\n }\n\n return result;\n}\n","import { getDb } from \"../db.js\";\nimport { getNodeOrThrow, getNode, getChildren, updateNode } from \"../nodes.js\";\nimport { getEdgesFrom, getEdgesTo, findNewlyActionable } from \"../edges.js\";\nimport { logEvent } from \"../events.js\";\nimport { requireArray, requireString, EngineError } from \"../validate.js\";\nimport type { Evidence } from \"../types.js\";\n\nexport interface MoveOp {\n op: \"move\";\n node_id: string;\n new_parent: string;\n}\n\nexport interface MergeOp {\n op: \"merge\";\n source: string;\n target: string;\n}\n\nexport interface DropOp {\n op: \"drop\";\n node_id: string;\n reason: string;\n}\n\nexport interface DeleteOp {\n op: \"delete\";\n node_id: string;\n}\n\nexport type RestructureOp = MoveOp | MergeOp | DropOp | DeleteOp;\n\nexport interface RestructureInput {\n operations: RestructureOp[];\n}\n\nexport interface RestructureResult {\n applied: number;\n details: Array<{ op: string; node_id: string; result: string }>;\n newly_actionable?: Array<{ id: string; summary: string }>;\n}\n\nfunction wouldCreateParentCycle(nodeId: string, newParentId: string): boolean {\n // Check if newParentId is a descendant of nodeId (which would create a cycle)\n const db = getDb();\n let current: string | null = newParentId;\n\n while (current) {\n if (current === nodeId) return true;\n const row = db\n .prepare(\"SELECT parent FROM nodes WHERE id = ?\")\n .get(current) as { parent: string | null } | undefined;\n current = row?.parent ?? null;\n }\n\n return false;\n}\n\nfunction getAllDescendants(nodeId: string): string[] {\n const ids: string[] = [];\n const stack = [nodeId];\n\n while (stack.length > 0) {\n const current = stack.pop()!;\n const children = getChildren(current);\n for (const child of children) {\n ids.push(child.id);\n stack.push(child.id);\n }\n }\n\n return ids;\n}\n\nfunction recomputeSubtreeDepth(nodeId: string, newDepth: number): void {\n const db = getDb();\n db.prepare(\"UPDATE nodes SET depth = ? WHERE id = ?\").run(newDepth, nodeId);\n const children = db.prepare(\"SELECT id FROM nodes WHERE parent = ?\").all(nodeId) as Array<{ id: string }>;\n for (const child of children) {\n recomputeSubtreeDepth(child.id, newDepth + 1);\n }\n}\n\nfunction handleMove(op: MoveOp, agent: string): { node_id: string; result: string } {\n const db = getDb();\n const node = getNodeOrThrow(op.node_id);\n const newParent = getNodeOrThrow(op.new_parent);\n\n if (node.project !== newParent.project) {\n throw new EngineError(\"cross_project\", `Cannot move node across projects: \"${node.project}\" → \"${newParent.project}\"`);\n }\n\n if (wouldCreateParentCycle(op.node_id, op.new_parent)) {\n throw new EngineError(\n \"cycle_detected\",\n `Move would create cycle: ${op.node_id} cannot be moved under ${op.new_parent}`\n );\n }\n\n const oldParent = node.parent;\n const now = new Date().toISOString();\n db.prepare(\"UPDATE nodes SET parent = ?, updated_at = ? WHERE id = ?\").run(\n op.new_parent,\n now,\n op.node_id\n );\n\n // Recompute depth for moved node and all descendants\n recomputeSubtreeDepth(op.node_id, newParent.depth + 1);\n\n logEvent(op.node_id, agent, \"moved\", [\n { field: \"parent\", before: oldParent, after: op.new_parent },\n ]);\n\n return { node_id: op.node_id, result: `moved under ${op.new_parent}` };\n}\n\nfunction handleMerge(op: MergeOp, agent: string): { node_id: string; result: string } {\n const db = getDb();\n const source = getNodeOrThrow(op.source);\n const target = getNodeOrThrow(op.target);\n\n if (source.project !== target.project) {\n throw new EngineError(\"cross_project\", `Cannot merge nodes across projects: \"${source.project}\" → \"${target.project}\"`);\n }\n\n // Move source's children to target and recompute their depths\n const movedChildren = db.prepare(\"SELECT id FROM nodes WHERE parent = ?\").all(op.source) as Array<{ id: string }>;\n db.prepare(\"UPDATE nodes SET parent = ?, updated_at = ? WHERE parent = ?\").run(\n op.target,\n new Date().toISOString(),\n op.source\n );\n for (const child of movedChildren) {\n recomputeSubtreeDepth(child.id, target.depth + 1);\n }\n\n // Append source's evidence to target\n const targetEvidence: Evidence[] = [...target.evidence, ...source.evidence];\n db.prepare(\"UPDATE nodes SET evidence = ?, updated_at = ? WHERE id = ?\").run(\n JSON.stringify(targetEvidence),\n new Date().toISOString(),\n op.target\n );\n\n // Transfer source's dependency edges to target\n const sourceOutEdges = getEdgesFrom(op.source);\n const sourceInEdges = getEdgesTo(op.source);\n\n for (const edge of sourceOutEdges) {\n // source depends_on X -> target depends_on X\n const existing = db\n .prepare(\n \"SELECT id FROM edges WHERE from_node = ? AND to_node = ? AND type = ?\"\n )\n .get(op.target, edge.to_node, edge.type);\n\n if (!existing) {\n db.prepare(\n \"UPDATE edges SET from_node = ? WHERE id = ?\"\n ).run(op.target, edge.id);\n } else {\n db.prepare(\"DELETE FROM edges WHERE id = ?\").run(edge.id);\n }\n }\n\n for (const edge of sourceInEdges) {\n // X depends_on source -> X depends_on target\n const existing = db\n .prepare(\n \"SELECT id FROM edges WHERE from_node = ? AND to_node = ? AND type = ?\"\n )\n .get(edge.from_node, op.target, edge.type);\n\n if (!existing) {\n db.prepare(\n \"UPDATE edges SET to_node = ? WHERE id = ?\"\n ).run(op.target, edge.id);\n } else {\n db.prepare(\"DELETE FROM edges WHERE id = ?\").run(edge.id);\n }\n }\n\n // Log merge on target (source will be deleted)\n logEvent(op.target, agent, \"merged\", [\n { field: \"merged_from\", before: null, after: op.source },\n ]);\n\n // Delete source: events, edges, then node (FK order)\n db.prepare(\"DELETE FROM events WHERE node_id = ?\").run(op.source);\n db.prepare(\"DELETE FROM edges WHERE from_node = ? OR to_node = ?\").run(\n op.source,\n op.source\n );\n db.prepare(\"DELETE FROM nodes WHERE id = ?\").run(op.source);\n\n return { node_id: op.target, result: `merged ${op.source} into ${op.target}` };\n}\n\nfunction handleDrop(op: DropOp, agent: string): { node_id: string; result: string } {\n const now = new Date().toISOString();\n\n // Get all descendants\n const descendants = getAllDescendants(op.node_id);\n const allIds = [op.node_id, ...descendants];\n\n // Mark all as resolved with evidence\n for (const id of allIds) {\n const node = getNode(id);\n if (!node || node.resolved) continue;\n\n updateNode({\n node_id: id,\n agent,\n resolved: true,\n add_evidence: [{ type: \"dropped\", ref: op.reason }],\n });\n\n logEvent(id, agent, \"dropped\", [\n { field: \"resolved\", before: false, after: true },\n { field: \"reason\", before: null, after: op.reason },\n ]);\n }\n\n return {\n node_id: op.node_id,\n result: `dropped ${allIds.length} node(s): ${op.reason}`,\n };\n}\n\nfunction handleDelete(op: DeleteOp, agent: string): { node_id: string; result: string } {\n const db = getDb();\n getNodeOrThrow(op.node_id);\n\n const descendants = getAllDescendants(op.node_id);\n const allIds = [op.node_id, ...descendants];\n const placeholders = allIds.map(() => \"?\").join(\",\");\n\n // Delete events, edges, then nodes (FK order)\n db.prepare(`DELETE FROM events WHERE node_id IN (${placeholders})`).run(...allIds);\n db.prepare(`DELETE FROM edges WHERE from_node IN (${placeholders}) OR to_node IN (${placeholders})`).run(...allIds, ...allIds);\n db.prepare(`DELETE FROM nodes WHERE id IN (${placeholders})`).run(...allIds);\n\n return {\n node_id: op.node_id,\n result: `deleted ${allIds.length} node(s)`,\n };\n}\n\nexport function handleRestructure(\n input: RestructureInput,\n agent: string\n): RestructureResult {\n const operations = requireArray<RestructureOp>(input?.operations, \"operations\");\n\n for (let i = 0; i < operations.length; i++) {\n const op = operations[i];\n requireString(op.op, `operations[${i}].op`);\n if (op.op === \"move\") {\n requireString((op as MoveOp).node_id, `operations[${i}].node_id`);\n requireString((op as MoveOp).new_parent, `operations[${i}].new_parent`);\n } else if (op.op === \"merge\") {\n requireString((op as MergeOp).source, `operations[${i}].source`);\n requireString((op as MergeOp).target, `operations[${i}].target`);\n } else if (op.op === \"drop\") {\n requireString((op as DropOp).node_id, `operations[${i}].node_id`);\n requireString((op as DropOp).reason, `operations[${i}].reason`);\n } else if (op.op === \"delete\") {\n requireString((op as DeleteOp).node_id, `operations[${i}].node_id`);\n } else {\n throw new EngineError(\"unknown_op\", `Unknown operation: ${op.op}`);\n }\n }\n\n const db = getDb();\n let applied = 0;\n const details: Array<{ op: string; node_id: string; result: string }> = [];\n let project: string | null = null;\n\n const transaction = db.transaction(() => {\n for (const op of operations) {\n let detail: { node_id: string; result: string };\n\n switch (op.op) {\n case \"move\":\n detail = handleMove(op, agent);\n project = getNode(op.node_id)?.project ?? project;\n break;\n case \"merge\":\n detail = handleMerge(op, agent);\n project = getNode(op.target)?.project ?? project;\n break;\n case \"drop\":\n detail = handleDrop(op, agent);\n project = getNode(op.node_id)?.project ?? project;\n break;\n case \"delete\":\n project = getNode(op.node_id)?.project ?? project;\n detail = handleDelete(op, agent);\n break;\n default:\n throw new Error(`Unknown operation: ${(op as RestructureOp).op}`);\n }\n\n details.push({ op: op.op, ...detail });\n applied++;\n }\n });\n\n transaction();\n\n const result: RestructureResult = { applied, details };\n\n if (project) {\n const actionable = findNewlyActionable(project);\n if (actionable.length > 0) {\n result.newly_actionable = actionable;\n }\n }\n\n return result;\n}\n","import { getEvents } from \"../events.js\";\nimport { getNodeOrThrow } from \"../nodes.js\";\nimport { requireString, optionalNumber, optionalString } from \"../validate.js\";\n\nexport interface HistoryInput {\n node_id: string;\n limit?: number;\n cursor?: string;\n}\n\nexport interface HistoryResult {\n events: Array<{\n timestamp: string;\n agent: string;\n action: string;\n changes: Array<{ field: string; before: unknown; after: unknown }>;\n }>;\n next_cursor?: string;\n}\n\nexport function handleHistory(input: HistoryInput): HistoryResult {\n const nodeId = requireString(input?.node_id, \"node_id\");\n const limit = optionalNumber(input?.limit, \"limit\", 1, 100) ?? 20;\n const cursor = optionalString(input?.cursor, \"cursor\");\n\n getNodeOrThrow(nodeId);\n\n const { events, next_cursor } = getEvents(nodeId, limit, cursor);\n\n const result: HistoryResult = {\n events: events.map((e) => ({\n timestamp: e.timestamp,\n agent: e.agent,\n action: e.action,\n changes: e.changes,\n })),\n };\n\n if (next_cursor) {\n result.next_cursor = next_cursor;\n }\n\n return result;\n}\n","import { getDb } from \"../db.js\";\nimport { getProjectRoot, getProjectSummary, listProjects } from \"../nodes.js\";\nimport { optionalString, optionalNumber } from \"../validate.js\";\nimport { EngineError } from \"../validate.js\";\nimport type { NodeRow, Evidence } from \"../types.js\";\n\n// [sl:yosc4NuV6j43Zv0fsDXDj] graph_onboard — single-call orientation for new agents\n\nexport interface OnboardInput {\n project?: string;\n evidence_limit?: number;\n}\n\nexport interface OnboardResult {\n project: string;\n goal: string;\n discovery: string | null;\n hint?: string;\n summary: {\n total: number;\n resolved: number;\n unresolved: number;\n blocked: number;\n actionable: number;\n };\n tree: Array<{\n id: string;\n summary: string;\n resolved: boolean;\n children: Array<{\n id: string;\n summary: string;\n resolved: boolean;\n child_count: number;\n }>;\n }>;\n recent_evidence: Array<{\n node_id: string;\n node_summary: string;\n type: string;\n ref: string;\n agent: string;\n timestamp: string;\n }>;\n context_links: string[];\n knowledge: Array<{\n key: string;\n content: string;\n updated_at: string;\n }>;\n recently_resolved: Array<{\n id: string;\n summary: string;\n resolved_at: string;\n agent: string;\n }>;\n last_activity: string | null;\n actionable: Array<{\n id: string;\n summary: string;\n properties: Record<string, unknown>;\n }>;\n}\n\n// [sl:1pRRsWFomcv04XAkdLMAj] Allow graph_onboard without project name\nexport function handleOnboard(input: OnboardInput): OnboardResult | { projects: ReturnType<typeof listProjects>; hint: string } {\n const evidenceLimit = optionalNumber(input?.evidence_limit, \"evidence_limit\", 1, 50) ?? 20;\n const db = getDb();\n\n // Auto-resolve project when not specified\n let project = optionalString(input?.project, \"project\");\n if (!project) {\n const projects = listProjects();\n if (projects.length === 0) {\n return {\n projects: [],\n hint: \"No projects yet. Create one with graph_open({ project: \\\"my-project\\\", goal: \\\"...\\\" }).\",\n };\n }\n if (projects.length === 1) {\n project = projects[0].project;\n } else {\n return {\n projects,\n hint: `${projects.length} projects found. Call graph_onboard with a specific project name.`,\n };\n }\n }\n\n // Verify project exists\n const root = getProjectRoot(project);\n if (!root) {\n throw new EngineError(\"project_not_found\", `Project not found: ${project}`);\n }\n\n // 1. Project summary counts\n const summary = getProjectSummary(project);\n\n // 2. Tree structure — root's children + their children (depth 1-2)\n const topChildren = db\n .prepare(\"SELECT * FROM nodes WHERE parent = ? ORDER BY created_at ASC\")\n .all(root.id) as NodeRow[];\n\n const tree = topChildren.map((child) => {\n const grandchildren = db\n .prepare(\n `SELECT id, summary, resolved,\n (SELECT COUNT(*) FROM nodes gc WHERE gc.parent = n.id) as child_count\n FROM nodes n WHERE parent = ? ORDER BY created_at ASC`\n )\n .all(child.id) as Array<{\n id: string;\n summary: string;\n resolved: number;\n child_count: number;\n }>;\n\n return {\n id: child.id,\n summary: child.summary,\n resolved: child.resolved === 1,\n discovery: child.discovery,\n children: grandchildren.map((gc) => ({\n id: gc.id,\n summary: gc.summary,\n resolved: gc.resolved === 1,\n child_count: gc.child_count,\n })),\n };\n });\n\n // 3. Recent evidence across all resolved nodes, sorted by timestamp\n const allNodes = db\n .prepare(\"SELECT id, summary, evidence FROM nodes WHERE project = ? AND resolved = 1 AND evidence != '[]'\")\n .all(project) as Array<{ id: string; summary: string; evidence: string }>;\n\n const allEvidence: OnboardResult[\"recent_evidence\"] = [];\n for (const node of allNodes) {\n const evidence: Evidence[] = JSON.parse(node.evidence);\n for (const ev of evidence) {\n allEvidence.push({\n node_id: node.id,\n node_summary: node.summary,\n type: ev.type,\n ref: ev.ref,\n agent: ev.agent,\n timestamp: ev.timestamp,\n });\n }\n }\n allEvidence.sort((a, b) => b.timestamp.localeCompare(a.timestamp));\n const recent_evidence = allEvidence.slice(0, evidenceLimit);\n\n // 4. All context_links aggregated and deduplicated\n const linkRows = db\n .prepare(\"SELECT context_links FROM nodes WHERE project = ? AND context_links != '[]'\")\n .all(project) as Array<{ context_links: string }>;\n\n const linkSet = new Set<string>();\n for (const row of linkRows) {\n const links: string[] = JSON.parse(row.context_links);\n for (const link of links) {\n linkSet.add(link);\n }\n }\n const context_links = [...linkSet].sort();\n\n // 5. Knowledge entries\n const knowledgeRows = db\n .prepare(\"SELECT key, content, updated_at FROM knowledge WHERE project = ? ORDER BY updated_at DESC\")\n .all(project) as Array<{ key: string; content: string; updated_at: string }>;\n\n // 6. Actionable tasks preview (like graph_next without claiming)\n const actionableRows = db\n .prepare(\n `SELECT n.id, n.summary, n.properties FROM nodes n\n WHERE n.project = ? AND n.resolved = 0\n AND NOT EXISTS (\n SELECT 1 FROM nodes child WHERE child.parent = n.id AND child.resolved = 0\n )\n AND NOT EXISTS (\n SELECT 1 FROM edges e\n JOIN nodes dep ON dep.id = e.to_node AND dep.resolved = 0\n WHERE e.from_node = n.id AND e.type = 'depends_on'\n )\n ORDER BY\n COALESCE(CAST(json_extract(n.properties, '$.priority') AS REAL), 0) DESC,\n n.depth DESC,\n n.updated_at ASC\n LIMIT 10`\n )\n .all(project) as Array<{ id: string; summary: string; properties: string }>;\n\n const actionable = actionableRows.map((row) => ({\n id: row.id,\n summary: row.summary,\n properties: JSON.parse(row.properties),\n }));\n\n // 7. Recently resolved nodes (last 24h) — cross-session continuity\n const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString();\n const recentlyResolvedRows = db\n .prepare(\n `SELECT id, summary, updated_at,\n (SELECT json_extract(value, '$.agent') FROM json_each(evidence) ORDER BY json_extract(value, '$.timestamp') DESC LIMIT 1) as last_agent\n FROM nodes\n WHERE project = ? AND resolved = 1 AND updated_at > ?\n ORDER BY updated_at DESC\n LIMIT 10`\n )\n .all(project, oneDayAgo) as Array<{ id: string; summary: string; updated_at: string; last_agent: string | null }>;\n\n const recently_resolved = recentlyResolvedRows.map((row) => ({\n id: row.id,\n summary: row.summary,\n resolved_at: row.updated_at,\n agent: row.last_agent ?? \"unknown\",\n }));\n\n // 8. Last activity timestamp\n const lastActivityRow = db\n .prepare(\"SELECT MAX(updated_at) as last FROM nodes WHERE project = ?\")\n .get(project) as { last: string | null };\n const last_activity = lastActivityRow.last;\n\n // Build hint based on project state\n let hint: string | undefined;\n if (root.discovery === \"pending\") {\n hint = `Discovery is pending. Interview the user to understand scope and goals, write knowledge entries with findings, then set discovery to \"done\" via graph_update before decomposing with graph_plan.`;\n } else if (actionable.length > 0) {\n const recentNote = recently_resolved.length > 0\n ? ` ${recently_resolved.length} task(s) resolved recently.`\n : \"\";\n hint = `${actionable.length} actionable task(s) ready.${recentNote} Use graph_next({ project: \"${project}\", claim: true }) to claim one.`;\n } else if (summary.unresolved > 0 && summary.actionable === 0) {\n hint = `All remaining tasks are blocked. Check dependencies with graph_query.`;\n } else if (summary.total <= 1 && root.discovery !== \"pending\") {\n hint = `Project is empty — use graph_plan to decompose the goal into tasks.`;\n }\n\n return {\n project,\n goal: root.summary,\n discovery: root.discovery,\n hint,\n summary,\n tree,\n recent_evidence,\n context_links,\n knowledge: knowledgeRows,\n recently_resolved,\n last_activity,\n actionable,\n };\n}\n","import { getProjectRoot, getChildren, getSubtreeProgress } from \"../nodes.js\";\nimport { requireString, optionalNumber } from \"../validate.js\";\nimport { EngineError } from \"../validate.js\";\nimport type { Node } from \"../types.js\";\n\n// [sl:ahq-BLHS9pJkJUlBZO92L] Full tree visualization — \"show me the whole tree\"\n\nexport interface TreeInput {\n project: string;\n depth?: number;\n}\n\ninterface TreeNode {\n id: string;\n summary: string;\n resolved: boolean;\n properties: Record<string, unknown>;\n progress?: { resolved: number; total: number };\n children?: TreeNode[];\n child_count?: number;\n}\n\nexport interface TreeResult {\n project: string;\n tree: TreeNode;\n stats: {\n total: number;\n resolved: number;\n unresolved: number;\n };\n}\n\nfunction buildTree(\n node: Node,\n currentDepth: number,\n maxDepth: number,\n stats: { total: number; resolved: number }\n): { treeNode: TreeNode; subtotal: number; subresolved: number } {\n stats.total++;\n if (node.resolved) stats.resolved++;\n\n const children = getChildren(node.id);\n const treeNode: TreeNode = {\n id: node.id,\n summary: node.summary,\n resolved: node.resolved,\n properties: node.properties,\n };\n\n let subtotal = 1;\n let subresolved = node.resolved ? 1 : 0;\n\n if (children.length === 0) return { treeNode, subtotal, subresolved };\n\n if (currentDepth < maxDepth) {\n treeNode.children = [];\n for (const child of children) {\n const result = buildTree(child, currentDepth + 1, maxDepth, stats);\n treeNode.children.push(result.treeNode);\n subtotal += result.subtotal;\n subresolved += result.subresolved;\n }\n } else {\n treeNode.child_count = children.length;\n // Count descendants via SQL when truncating at depth limit\n const progress = getSubtreeProgress(node.id);\n subtotal = progress.total;\n subresolved = progress.resolved;\n }\n\n treeNode.progress = { resolved: subresolved, total: subtotal };\n return { treeNode, subtotal, subresolved };\n}\n\nexport function handleTree(input: TreeInput): TreeResult {\n const project = requireString(input?.project, \"project\");\n const depth = optionalNumber(input?.depth, \"depth\", 1, 20) ?? 10;\n\n const root = getProjectRoot(project);\n if (!root) {\n throw new EngineError(\"project_not_found\", `Project not found: ${project}`);\n }\n\n const stats = { total: 0, resolved: 0 };\n const { treeNode } = buildTree(root, 0, depth, stats);\n\n return {\n project,\n tree: treeNode,\n stats: {\n total: stats.total,\n resolved: stats.resolved,\n unresolved: stats.total - stats.resolved,\n },\n };\n}\n","import { nanoid } from \"nanoid\";\nimport { getDb } from \"../db.js\";\nimport { getProjectRoot } from \"../nodes.js\";\nimport { EngineError, requireString } from \"../validate.js\";\n\n// [sl:4PrMkE09nf6ptz8LLR9rW] Knowledge tools — persistent project-level knowledge store\n\ninterface KnowledgeRow {\n id: string;\n project: string;\n key: string;\n content: string;\n created_by: string;\n created_at: string;\n updated_at: string;\n}\n\n// --- graph_knowledge_write ---\n\nexport interface KnowledgeWriteInput {\n project: string;\n key: string;\n content: string;\n}\n\nexport function handleKnowledgeWrite(input: KnowledgeWriteInput, agent: string) {\n const project = requireString(input.project, \"project\");\n const key = requireString(input.key, \"key\");\n const content = requireString(input.content, \"content\");\n\n const root = getProjectRoot(project);\n if (!root) {\n throw new EngineError(\"not_found\", `Project '${project}' not found`);\n }\n\n const db = getDb();\n const now = new Date().toISOString();\n\n const existing = db\n .prepare(\"SELECT id FROM knowledge WHERE project = ? AND key = ?\")\n .get(project, key) as { id: string } | undefined;\n\n if (existing) {\n db.prepare(\n \"UPDATE knowledge SET content = ?, updated_at = ? WHERE id = ?\"\n ).run(content, now, existing.id);\n return { key, action: \"updated\" };\n } else {\n const id = nanoid();\n db.prepare(\n \"INSERT INTO knowledge (id, project, key, content, created_by, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)\"\n ).run(id, project, key, content, agent, now, now);\n return { key, action: \"created\" };\n }\n}\n\n// --- graph_knowledge_read ---\n\nexport interface KnowledgeReadInput {\n project: string;\n key?: string;\n}\n\nexport function handleKnowledgeRead(input: KnowledgeReadInput) {\n const project = requireString(input.project, \"project\");\n\n const root = getProjectRoot(project);\n if (!root) {\n throw new EngineError(\"not_found\", `Project '${project}' not found`);\n }\n\n const db = getDb();\n\n if (input.key) {\n const row = db\n .prepare(\"SELECT * FROM knowledge WHERE project = ? AND key = ?\")\n .get(project, input.key) as KnowledgeRow | undefined;\n\n if (!row) {\n throw new EngineError(\"not_found\", `Knowledge entry '${input.key}' not found in project '${project}'`);\n }\n\n return {\n key: row.key,\n content: row.content,\n updated_at: row.updated_at,\n created_by: row.created_by,\n };\n }\n\n // List all\n const rows = db\n .prepare(\"SELECT key, content, updated_at, created_by FROM knowledge WHERE project = ? ORDER BY updated_at DESC\")\n .all(project) as Array<{ key: string; content: string; updated_at: string; created_by: string }>;\n\n return { entries: rows };\n}\n\n// --- graph_knowledge_delete ---\n\nexport interface KnowledgeDeleteInput {\n project: string;\n key: string;\n}\n\nexport function handleKnowledgeDelete(input: KnowledgeDeleteInput) {\n const project = requireString(input.project, \"project\");\n const key = requireString(input.key, \"key\");\n\n const root = getProjectRoot(project);\n if (!root) {\n throw new EngineError(\"not_found\", `Project '${project}' not found`);\n }\n\n const db = getDb();\n const result = db\n .prepare(\"DELETE FROM knowledge WHERE project = ? AND key = ?\")\n .run(project, key);\n\n if (result.changes === 0) {\n throw new EngineError(\"not_found\", `Knowledge entry '${key}' not found in project '${project}'`);\n }\n\n return { key, action: \"deleted\" };\n}\n\n// --- graph_knowledge_search ---\n\nexport interface KnowledgeSearchInput {\n project: string;\n query: string;\n}\n\nexport function handleKnowledgeSearch(input: KnowledgeSearchInput) {\n const project = requireString(input.project, \"project\");\n const query = requireString(input.query, \"query\");\n\n const root = getProjectRoot(project);\n if (!root) {\n throw new EngineError(\"not_found\", `Project '${project}' not found`);\n }\n\n const db = getDb();\n const pattern = `%${query}%`;\n\n const rows = db\n .prepare(\n \"SELECT key, content, updated_at, created_by FROM knowledge WHERE project = ? AND (key LIKE ? OR content LIKE ?) ORDER BY updated_at DESC\"\n )\n .all(project, pattern, pattern) as Array<{ key: string; content: string; updated_at: string; created_by: string }>;\n\n return { entries: rows, query };\n}\n","import { getDb } from \"./db.js\";\nimport { EngineError } from \"./validate.js\";\nimport type { Tier } from \"./license.js\";\n\n// [sl:N0IDVJQIhENQFsov6-Lhg] Feature gates — enforce free vs pro limits\n\n// Limits relaxed — everything free while building user base (Phase 1: Acquisition)\nconst FREE_LIMITS = {\n maxProjects: Infinity,\n maxNodesPerProject: Infinity,\n onboardEvidenceLimit: 50,\n scopeEnabled: true,\n};\n\n/**\n * Check if creating nodes would exceed the free tier node limit.\n * Throws EngineError if limit would be exceeded.\n */\nexport function checkNodeLimit(tier: Tier, project: string, adding: number): void {\n if (tier === \"pro\") return;\n\n const db = getDb();\n const { count } = db\n .prepare(\"SELECT COUNT(*) as count FROM nodes WHERE project = ?\")\n .get(project) as { count: number };\n\n if (count + adding > FREE_LIMITS.maxNodesPerProject) {\n throw new EngineError(\n \"free_tier_limit\",\n `Free tier is limited to ${FREE_LIMITS.maxNodesPerProject} nodes per project. ` +\n `Current: ${count}, adding: ${adding}. Activate a license key to remove this limit.`\n );\n }\n}\n\n/**\n * Check if creating a new project would exceed the free tier project limit.\n * Throws EngineError if limit would be exceeded.\n */\nexport function checkProjectLimit(tier: Tier): void {\n if (tier === \"pro\") return;\n\n const db = getDb();\n const { count } = db\n .prepare(\"SELECT COUNT(*) as count FROM nodes WHERE parent IS NULL\")\n .get() as { count: number };\n\n if (count >= FREE_LIMITS.maxProjects) {\n throw new EngineError(\n \"free_tier_limit\",\n `Free tier is limited to ${FREE_LIMITS.maxProjects} project. ` +\n `Activate a license key to create unlimited projects.`\n );\n }\n}\n\n/**\n * Cap the evidence limit for graph_onboard on free tier.\n */\nexport function capEvidenceLimit(tier: Tier, requested?: number): number {\n const max = tier === \"pro\" ? (requested ?? 20) : FREE_LIMITS.onboardEvidenceLimit;\n return Math.min(requested ?? max, tier === \"pro\" ? 50 : FREE_LIMITS.onboardEvidenceLimit);\n}\n\n/**\n * Check if knowledge tools are allowed on the current tier.\n * Currently free for all — everything ungated during acquisition phase.\n */\nexport function checkKnowledgeTier(_tier: Tier): void {\n // All tiers allowed during acquisition phase\n return;\n}\n\n/**\n * Check if scope parameter is allowed.\n * Currently free for all during acquisition phase.\n */\nexport function checkScope(_tier: Tier, scope?: string): string | undefined {\n return scope;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA,SAAS,cAAc;AACvB,SAAS,4BAA4B;AACrC;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACK;;;AC2BA,SAAS,WAAW,OAAkB,OAA2B;AACtE,QAAM,UAAU,eAAe,OAAO,SAAS,SAAS;AACxD,QAAM,OAAO,eAAe,OAAO,MAAM,MAAM;AAE/C,MAAI,CAAC,SAAS;AACZ,WAAO,EAAE,UAAU,aAAa,EAAE;AAAA,EACpC;AAEA,MAAI,OAAO,eAAe,OAAO;AACjC,MAAI,QAAQ;AAEZ,MAAI,CAAC,MAAM;AACT,WAAO,WAAW;AAAA,MAChB;AAAA,MACA,SAAS,QAAQ;AAAA,MACjB,WAAW,OAAO,iBAAiB,SAAS;AAAA,MAC5C;AAAA,IACF,CAAC;AACD,YAAQ;AAAA,EACV;AAEA,QAAM,UAAU,kBAAkB,OAAO;AAEzC,QAAM,SAAqB,EAAE,SAAS,MAAM,QAAQ;AAGpD,MAAI,SAAS,KAAK,cAAc,WAAW;AACzC,WAAO,OAAO;AAAA,EAChB,WAAW,OAAO;AAChB,WAAO,OAAO;AAAA,EAChB,WAAW,KAAK,cAAc,WAAW;AACvC,WAAO,OAAO;AAAA,EAChB,WAAW,QAAQ,aAAa,GAAG;AACjC,WAAO,OAAO,GAAG,QAAQ,UAAU;AAAA,EACrC,WAAW,QAAQ,aAAa,KAAK,QAAQ,eAAe,GAAG;AAC7D,WAAO,OAAO;AAAA,EAChB;AAEA,SAAO;AACT;;;AC1EA,SAAS,cAAc;AAOvB,SAAS,iBAAiB,MAAc,IAAqB;AAG3D,QAAM,KAAK,MAAM;AACjB,QAAM,UAAU,oBAAI,IAAY;AAChC,QAAM,QAAQ,CAAC,EAAE;AAEjB,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,IAAI;AAC1B,QAAI,YAAY,KAAM,QAAO;AAC7B,QAAI,QAAQ,IAAI,OAAO,EAAG;AAC1B,YAAQ,IAAI,OAAO;AAGnB,UAAM,OAAO,GACV;AAAA,MACC;AAAA,IACF,EACC,IAAI,OAAO;AAEd,eAAW,OAAO,MAAM;AACtB,YAAM,KAAK,IAAI,OAAO;AAAA,IACxB;AAAA,EACF;AAEA,SAAO;AACT;AAiBO,SAAS,QAAQ,OAAoC;AAC1D,QAAM,KAAK,MAAM;AAGjB,QAAM,aAAa,GAAG,QAAQ,mCAAmC,EAAE,IAAI,MAAM,IAAI;AACjF,QAAM,WAAW,GAAG,QAAQ,mCAAmC,EAAE,IAAI,MAAM,EAAE;AAE7E,MAAI,CAAC,YAAY;AACf,WAAO,EAAE,MAAM,MAAM,UAAU,MAAM,QAAQ,qBAAqB,MAAM,KAAK;AAAA,EAC/E;AACA,MAAI,CAAC,UAAU;AACb,WAAO,EAAE,MAAM,MAAM,UAAU,MAAM,QAAQ,qBAAqB,MAAM,GAAG;AAAA,EAC7E;AAGA,QAAM,WAAW,GACd;AAAA,IACC;AAAA,EACF,EACC,IAAI,MAAM,MAAM,MAAM,IAAI,MAAM,IAAI;AAEvC,MAAI,UAAU;AACZ,WAAO,EAAE,MAAM,MAAM,UAAU,MAAM,QAAQ,iBAAiB;AAAA,EAChE;AAGA,MAAI,MAAM,SAAS,cAAc;AAC/B,QAAI,iBAAiB,MAAM,MAAM,MAAM,EAAE,GAAG;AAC1C,aAAO,EAAE,MAAM,MAAM,UAAU,MAAM,QAAQ,iBAAiB;AAAA,IAChE;AAAA,EACF;AAEA,QAAM,OAAa;AAAA,IACjB,IAAI,OAAO;AAAA,IACX,WAAW,MAAM;AAAA,IACjB,SAAS,MAAM;AAAA,IACf,MAAM,MAAM;AAAA,IACZ,aAAY,oBAAI,KAAK,GAAE,YAAY;AAAA,EACrC;AAEA,KAAG,QAAQ;AAAA;AAAA;AAAA,GAGV,EAAE,IAAI,KAAK,IAAI,KAAK,WAAW,KAAK,SAAS,KAAK,MAAM,KAAK,UAAU;AAExE,WAAS,MAAM,MAAM,MAAM,OAAO,cAAc;AAAA,IAC9C,EAAE,OAAO,QAAQ,QAAQ,MAAM,OAAO,EAAE,IAAI,MAAM,IAAI,MAAM,MAAM,KAAK,EAAE;AAAA,EAC3E,CAAC;AAED,SAAO,EAAE,MAAM,UAAU,MAAM;AACjC;AAIO,SAAS,WACd,MACA,IACA,MACA,OACS;AACT,QAAM,KAAK,MAAM;AAEjB,QAAM,SAAS,GACZ;AAAA,IACC;AAAA,EACF,EACC,IAAI,MAAM,IAAI,IAAI;AAErB,MAAI,OAAO,UAAU,GAAG;AACtB,aAAS,MAAM,OAAO,gBAAgB;AAAA,MACpC,EAAE,OAAO,QAAQ,QAAQ,EAAE,IAAI,KAAK,GAAG,OAAO,KAAK;AAAA,IACrD,CAAC;AACD,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAIO,SAAS,aAAa,QAAgB,MAAuB;AAClE,QAAM,KAAK,MAAM;AAEjB,MAAI,MAAM;AACR,WAAO,GACJ,QAAQ,sDAAsD,EAC9D,IAAI,QAAQ,IAAI;AAAA,EACrB;AAEA,SAAO,GACJ,QAAQ,yCAAyC,EACjD,IAAI,MAAM;AACf;AAEO,SAAS,WAAW,QAAgB,MAAuB;AAChE,QAAM,KAAK,MAAM;AAEjB,MAAI,MAAM;AACR,WAAO,GACJ,QAAQ,oDAAoD,EAC5D,IAAI,QAAQ,IAAI;AAAA,EACrB;AAEA,SAAO,GACJ,QAAQ,uCAAuC,EAC/C,IAAI,MAAM;AACf;AAMO,SAAS,oBACd,SACA,iBACwC;AACxC,QAAM,KAAK,MAAM;AAEjB,MAAI,mBAAmB,gBAAgB,SAAS,GAAG;AAEjD,UAAM,eAAe,gBAAgB,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG;AAC5D,UAAMA,QAAO,GACV;AAAA,MACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,6DAMqD,YAAY;AAAA;AAAA;AAAA;AAAA,4DAIb,YAAY;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAYlE,EACC,IAAI,SAAS,GAAG,iBAAiB,GAAG,eAAe;AAKtD,WAAOA;AAAA,EACT;AAGA,QAAM,OAAO,GACV;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUF,EACC,IAAI,OAAO;AAEd,SAAO;AACT;;;ACvMO,SAAS,WAAW,OAAkB,OAA2B;AACtE,QAAM,KAAK,MAAM;AACjB,QAAM,QAAQ,aAA4B,OAAO,OAAO,OAAO;AAG/D,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,UAAM,IAAI,MAAM,CAAC;AACjB,kBAAc,EAAE,KAAK,SAAS,CAAC,OAAO;AACtC,kBAAc,EAAE,SAAS,SAAS,CAAC,WAAW;AAAA,EAChD;AAGA,QAAM,SAAS,oBAAI,IAAoB;AACvC,QAAM,UAA8C,CAAC;AAGrD,QAAM,OAAO,oBAAI,IAAY;AAC7B,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,IAAI,KAAK,GAAG,GAAG;AACtB,YAAM,IAAI,YAAY,iBAAiB,2BAA2B,KAAK,GAAG,EAAE;AAAA,IAC9E;AACA,SAAK,IAAI,KAAK,GAAG;AAAA,EACnB;AAGA,QAAM,cAAc,GAAG,YAAY,MAAM;AAEvC,eAAW,aAAa,OAAO;AAE7B,UAAI;AACJ,UAAI,UAAU,YAAY;AAExB,mBAAW,OAAO,IAAI,UAAU,UAAU;AAC1C,YAAI,CAAC,UAAU;AAEb,gBAAM,WAAW,QAAQ,UAAU,UAAU;AAC7C,cAAI,UAAU;AACZ,uBAAW,SAAS;AAAA,UACtB,OAAO;AACL,kBAAM,IAAI;AAAA,cACR;AAAA,cACA,eAAe,UAAU,UAAU;AAAA,YACrC;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAGA,UAAI;AACJ,UAAI,UAAU;AACZ,cAAM,aAAa,QAAQ,QAAQ;AAEnC,YAAI,WAAW,cAAc,WAAW;AACtC,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,2BAA2B,WAAW,OAAO,MAAM,QAAQ,4EAAuE,QAAQ;AAAA,UAC5I;AAAA,QACF;AACA,kBAAU,WAAW;AAAA,MACvB,OAAO;AAGL,cAAM,IAAI;AAAA,UACR;AAAA,UACA,SAAS,UAAU,GAAG;AAAA,QACxB;AAAA,MACF;AAEA,YAAM,OAAO,WAAW;AAAA,QACtB;AAAA,QACA,QAAQ;AAAA,QACR,SAAS,UAAU;AAAA,QACnB,eAAe,UAAU;AAAA,QACzB,YAAY,UAAU;AAAA,QACtB;AAAA,MACF,CAAC;AAED,aAAO,IAAI,UAAU,KAAK,KAAK,EAAE;AACjC,cAAQ,KAAK,EAAE,KAAK,UAAU,KAAK,IAAI,KAAK,GAAG,CAAC;AAAA,IAClD;AAGA,eAAW,aAAa,OAAO;AAC7B,UAAI,CAAC,UAAU,cAAc,UAAU,WAAW,WAAW,EAAG;AAEhE,YAAM,SAAS,OAAO,IAAI,UAAU,GAAG;AAEvC,iBAAW,OAAO,UAAU,YAAY;AAEtC,YAAI,OAAO,OAAO,IAAI,GAAG;AACzB,YAAI,CAAC,MAAM;AACT,gBAAM,WAAW,QAAQ,GAAG;AAC5B,cAAI,UAAU;AACZ,mBAAO,SAAS;AAAA,UAClB,OAAO;AACL,kBAAM,IAAI;AAAA,cACR;AAAA,cACA,eAAe,GAAG,cAAc,UAAU,GAAG;AAAA,YAC/C;AAAA,UACF;AAAA,QACF;AAEA,cAAM,SAAS,QAAQ;AAAA,UACrB,MAAM;AAAA,UACN,IAAI;AAAA,UACJ,MAAM;AAAA,UACN;AAAA,QACF,CAAC;AAED,YAAI,OAAO,UAAU;AACnB,gBAAM,IAAI;AAAA,YACR;AAAA,YACA,yBAAyB,UAAU,GAAG,SAAS,GAAG,eAAe,OAAO,MAAM;AAAA,UAChF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF,CAAC;AAED,cAAY;AAEZ,SAAO,EAAE,QAAQ;AACnB;;;AClHO,SAAS,aAAa,OAAoB,OAA6B;AAC5E,QAAM,UAAU,aAA0B,OAAO,SAAS,SAAS;AAEnE,WAAS,IAAI,GAAG,IAAI,QAAQ,QAAQ,KAAK;AACvC,kBAAc,QAAQ,CAAC,EAAE,SAAS,WAAW,CAAC,WAAW;AACzD,QAAI,QAAQ,CAAC,EAAE,cAAc;AAC3B,eAAS,IAAI,GAAG,IAAI,QAAQ,CAAC,EAAE,aAAc,QAAQ,KAAK;AACxD,sBAAc,QAAQ,CAAC,EAAE,aAAc,CAAC,EAAE,MAAM,WAAW,CAAC,kBAAkB,CAAC,QAAQ;AACvF,sBAAc,QAAQ,CAAC,EAAE,aAAc,CAAC,EAAE,KAAK,WAAW,CAAC,kBAAkB,CAAC,OAAO;AAAA,MACvF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,UAAmD,CAAC;AAC1D,QAAM,cAAwB,CAAC;AAC/B,QAAM,mBAAmB,oBAAI,IAAY;AAEzC,aAAW,SAAS,SAAS;AAE3B,QAAI,MAAM,iBAAiB,QAAW;AACpC,YAAM,UAAU,eAAe,MAAM,OAAO;AAC5C,UAAI,QAAQ,QAAQ,MAAM,cAAc;AACtC,cAAM,IAAI;AAAA,UACR;AAAA,UACA,QAAQ,MAAM,OAAO,YAAY,QAAQ,GAAG,cAAc,MAAM,YAAY;AAAA,QAC9E;AAAA,MACF;AAAA,IACF;AAGA,QAAI,WAAW,MAAM;AACrB,QAAI,MAAM,iBAAiB;AACzB,iBAAW,CAAC,GAAI,YAAY,CAAC,GAAI,EAAE,MAAM,QAAQ,KAAK,MAAM,gBAAgB,CAAC;AAAA,IAC/E;AAEA,UAAM,OAAO,WAAW;AAAA,MACtB,SAAS,MAAM;AAAA,MACf;AAAA,MACA,UAAU,MAAM;AAAA,MAChB,WAAW,MAAM;AAAA,MACjB,SAAS,MAAM;AAAA,MACf,gBAAgB,MAAM;AAAA,MACtB,OAAO,MAAM;AAAA,MACb,SAAS,MAAM;AAAA,MACf,YAAY,MAAM;AAAA,MAClB,mBAAmB,MAAM;AAAA,MACzB,sBAAsB,MAAM;AAAA,MAC5B,cAAc;AAAA,IAChB,CAAC;AAED,YAAQ,KAAK,EAAE,SAAS,KAAK,IAAI,KAAK,KAAK,IAAI,CAAC;AAEhD,QAAI,MAAM,aAAa,MAAM;AAC3B,kBAAY,KAAK,KAAK,EAAE;AACxB,uBAAiB,IAAI,KAAK,OAAO;AAAA,IACnC;AAAA,EACF;AAGA,QAAM,eAA4D,CAAC;AACnE,MAAI,YAAY,SAAS,GAAG;AAC1B,UAAM,OAAO,IAAI,IAAY,WAAW;AACxC,UAAM,QAAQ,CAAC,GAAG,WAAW;AAE7B,WAAO,MAAM,SAAS,GAAG;AACvB,YAAM,SAAS,MAAM,MAAM;AAC3B,YAAM,OAAO,QAAQ,MAAM;AAC3B,UAAI,CAAC,MAAM,OAAQ;AAEnB,YAAM,WAAW,KAAK;AACtB,UAAI,KAAK,IAAI,QAAQ,EAAG;AACxB,WAAK,IAAI,QAAQ;AAEjB,YAAM,SAAS,QAAQ,QAAQ;AAC/B,UAAI,CAAC,UAAU,OAAO,SAAU;AAEhC,YAAM,WAAW,YAAY,QAAQ;AACrC,UAAI,SAAS,WAAW,EAAG;AAC3B,UAAI,SAAS,MAAM,CAAC,MAAM,EAAE,QAAQ,GAAG;AACrC,cAAM,WAAW,WAAW;AAAA,UAC1B,SAAS;AAAA,UACT;AAAA,UACA,UAAU;AAAA,UACV,cAAc,CAAC,EAAE,MAAM,QAAQ,KAAK,wCAAwC,CAAC;AAAA,QAC/E,CAAC;AACD,gBAAQ,KAAK,EAAE,SAAS,SAAS,IAAI,KAAK,SAAS,IAAI,CAAC;AACxD,oBAAY,KAAK,QAAQ;AACzB,qBAAa,KAAK,EAAE,SAAS,UAAU,SAAS,OAAO,QAAQ,CAAC;AAChE,cAAM,KAAK,QAAQ;AAAA,MACrB;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAuB,EAAE,QAAQ;AAEvC,MAAI,YAAY,SAAS,KAAK,iBAAiB,OAAO,GAAG;AACvD,UAAM,gBAAwD,CAAC;AAC/D,eAAW,QAAQ,kBAAkB;AACnC,oBAAc,KAAK,GAAG,oBAAoB,MAAM,WAAW,CAAC;AAAA,IAC9D;AACA,WAAO,mBAAmB;AAAA,EAC5B;AAEA,MAAI,aAAa,SAAS,GAAG;AAC3B,WAAO,gBAAgB;AAAA,EACzB;AAEA,SAAO;AACT;;;ACvHO,SAAS,cAAc,OAAqB,OAA8B;AAC/E,QAAM,QAAQ,aAA+B,OAAO,OAAO,OAAO;AAElE,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,kBAAc,MAAM,CAAC,EAAE,MAAM,SAAS,CAAC,QAAQ;AAC/C,kBAAc,MAAM,CAAC,EAAE,IAAI,SAAS,CAAC,MAAM;AAC3C,kBAAc,MAAM,CAAC,EAAE,MAAM,SAAS,CAAC,QAAQ;AAAA,EACjD;AAEA,MAAI,UAAU;AACd,QAAM,WAAgE,CAAC;AAEvE,aAAW,QAAQ,OAAO;AACxB,QAAI,KAAK,SAAS,UAAU;AAC1B,eAAS,KAAK;AAAA,QACZ,MAAM,KAAK;AAAA,QACX,IAAI,KAAK;AAAA,QACT,QAAQ;AAAA,MACV,CAAC;AACD;AAAA,IACF;AAEA,QAAI,KAAK,QAAQ;AACf,YAAM,UAAU,WAAW,KAAK,MAAM,KAAK,IAAI,KAAK,MAAM,KAAK;AAC/D,UAAI,SAAS;AACX;AAAA,MACF,OAAO;AACL,iBAAS,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,IAAI,KAAK;AAAA,UACT,QAAQ;AAAA,QACV,CAAC;AAAA,MACH;AAAA,IACF,OAAO;AACL,YAAMC,UAAS,QAAQ;AAAA,QACrB,MAAM,KAAK;AAAA,QACX,IAAI,KAAK;AAAA,QACT,MAAM,KAAK;AAAA,QACX;AAAA,MACF,CAAC;AAED,UAAIA,QAAO,UAAU;AACnB,iBAAS,KAAK;AAAA,UACZ,MAAM,KAAK;AAAA,UACX,IAAI,KAAK;AAAA,UACT,QAAQA,QAAO;AAAA,QACjB,CAAC;AAAA,MACH,OAAO;AACL;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,QAAM,SAAwB,EAAE,QAAQ;AACxC,MAAI,SAAS,SAAS,GAAG;AACvB,WAAO,WAAW;AAAA,EACpB;AACA,SAAO;AACT;;;AC/CA,SAAS,cAAc,QAAgB,cAAsB,UAA4B;AACvF,QAAM,OAAO,eAAe,MAAM;AAClC,QAAM,WAAW,YAAY,MAAM;AAEnC,QAAM,OAAiB;AAAA,IACrB,IAAI,KAAK;AAAA,IACT,SAAS,KAAK;AAAA,IACd,UAAU,KAAK;AAAA,IACf,WAAW,KAAK;AAAA,IAChB,OAAO,KAAK;AAAA,EACd;AAEA,MAAI,SAAS,WAAW,GAAG;AACzB,WAAO;AAAA,EACT;AAEA,OAAK,WAAW,mBAAmB,MAAM;AAEzC,MAAI,eAAe,UAAU;AAC3B,SAAK,WAAW,SAAS;AAAA,MAAI,CAAC,UAC5B,cAAc,MAAM,IAAI,eAAe,GAAG,QAAQ;AAAA,IACpD;AAAA,EACF,OAAO;AACL,SAAK,cAAc,SAAS;AAAA,EAC9B;AAEA,SAAO;AACT;AAEO,SAAS,cAAc,OAAoC;AAChE,QAAM,SAAS,cAAc,OAAO,SAAS,SAAS;AACtD,QAAM,QAAQ,eAAe,OAAO,OAAO,SAAS,GAAG,EAAE,KAAK;AAC9D,QAAM,OAAO,eAAe,MAAM;AAClC,QAAM,YAAY,aAAa,MAAM;AAGrC,QAAM,WAAW,cAAc,QAAQ,GAAG,KAAK;AAG/C,QAAM,UAAU,aAAa,QAAQ,YAAY;AACjD,QAAM,SAAS,WAAW,QAAQ,YAAY;AAE9C,QAAM,aAAa,QAAQ,IAAI,CAAC,SAAS;AACvC,UAAM,SAAS,QAAQ,KAAK,OAAO;AACnC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,WAAW,QAAQ,YAAY;AAAA,IACjC;AAAA,EACF,CAAC;AAED,QAAM,cAAc,OAAO,IAAI,CAAC,SAAS;AACvC,UAAM,SAAS,QAAQ,KAAK,SAAS;AACrC,WAAO;AAAA,MACL,MAAM;AAAA,MACN,WAAW,KAAK;AAAA,IAClB;AAAA,EACF,CAAC;AAED,SAAO,EAAE,MAAM,WAAW,UAAU,YAAY,YAAY;AAC9D;;;AChDA,SAAS,iBAAiB,QAA0B;AAClD,QAAM,KAAK,MAAM;AACjB,QAAM,OAAO,GACV;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMF,EACC,IAAI,MAAM;AAEb,SAAO,KAAK,IAAI,CAAC,MAAM,EAAE,EAAE;AAC7B;AAGO,SAAS,YAAY,OAAgC;AAC1D,QAAM,UAAU,cAAc,OAAO,SAAS,SAAS;AACvD,QAAM,KAAK,MAAM;AACjB,QAAM,QAAQ,KAAK,IAAI,eAAe,OAAO,OAAO,SAAS,GAAG,GAAG,KAAK,IAAI,GAAG;AAC/E,QAAM,SAAS,OAAO;AACtB,QAAM,SAAS,eAAe,OAAO,QAAQ,QAAQ;AAGrD,QAAM,aAAuB,CAAC,eAAe;AAC7C,QAAM,SAAoB,CAAC,OAAO;AAElC,MAAI,QAAQ,aAAa,QAAW;AAClC,eAAW,KAAK,gBAAgB;AAChC,WAAO,KAAK,OAAO,WAAW,IAAI,CAAC;AAAA,EACrC;AAEA,MAAI,QAAQ,MAAM;AAChB,eAAW,KAAK,kBAAkB;AAClC,WAAO,KAAK,IAAI,OAAO,IAAI,GAAG;AAAA,EAChC;AAEA,MAAI,QAAQ,UAAU;AACpB,UAAM,gBAAgB,iBAAiB,OAAO,QAAQ;AACtD,QAAI,cAAc,WAAW,GAAG;AAC9B,aAAO,EAAE,OAAO,CAAC,GAAG,OAAO,EAAE;AAAA,IAC/B;AACA,eAAW,KAAK,YAAY,cAAc,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC,GAAG;AACrE,WAAO,KAAK,GAAG,aAAa;AAAA,EAC9B;AAEA,MAAI,QAAQ,mBAAmB;AAC7B,eAAW;AAAA,MACT;AAAA,IACF;AACA,WAAO,KAAK,OAAO,iBAAiB;AAAA,EACtC;AAEA,MAAI,QAAQ,SAAS;AACnB,eAAW;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,MAAI,QAAQ,eAAe;AACzB,eAAW,KAAK,gBAAgB;AAChC,eAAW,KAAK,eAAe;AAC/B,eAAW;AAAA,MACT;AAAA,IACF;AACA,eAAW;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA,IAKF;AAAA,EACF;AAEA,MAAI,QAAQ,YAAY;AACtB,eAAW,KAAK,gBAAgB;AAChC,eAAW;AAAA,MACT;AAAA;AAAA;AAAA;AAAA;AAAA,IAKF;AAAA,EACF;AAEA,MAAI,QAAQ,YAAY;AACtB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,OAAO,UAAU,GAAG;AAC5D,iBAAW,KAAK,mCAAmC;AACnD,aAAO,KAAK,KAAK,GAAG,IAAI,KAAwB;AAAA,IAClD;AAAA,EACF;AAEA,MAAI,QAAQ,eAAe,QAAW;AACpC,QAAI,OAAO,eAAe,MAAM;AAC9B,iBAAW;AAAA,QACT;AAAA,MACF;AAAA,IACF,OAAO;AACL,iBAAW,KAAK,iDAAiD;AACjE,aAAO,KAAK,OAAO,UAAU;AAAA,IAC/B;AAAA,EACF;AAGA,MAAI,QAAQ;AACV,UAAM,CAAC,YAAY,QAAQ,IAAI,OAAO,MAAM,GAAG;AAC/C,eAAW,KAAK,uDAAuD;AACvE,WAAO,KAAK,YAAY,YAAY,QAAQ;AAAA,EAC9C;AAEA,QAAM,cAAc,WAAW,KAAK,OAAO;AAG3C,MAAI;AACJ,UAAQ,MAAM,MAAM;AAAA,IAClB,KAAK;AAEH,gBAAU;AACV;AAAA,IACF,KAAK;AACH,gBAAU;AACV;AAAA,IACF,KAAK;AACH,gBAAU;AACV;AAAA,IACF,KAAK;AAAA,IACL;AACE,gBAAU;AACV;AAAA,EACJ;AAIA,QAAM,kBAAkB,SAAS,WAAW,MAAM,GAAG,EAAE,IAAI;AAC3D,QAAM,cAAc,SAAS,OAAO,MAAM,GAAG,EAAE,IAAI,CAAC,GAAG,MAAM;AAC7D,QAAM,QACJ,GAAG,QAAQ,+CAA+C,gBAAgB,KAAK,OAAO,CAAC,EAAE,EAAE,IAAI,GAAG,WAAW,EAC7G;AAGF,SAAO,KAAK,QAAQ,CAAC;AACrB,QAAM,QAAQ,+BAA+B,WAAW,aAAa,OAAO;AAC5E,QAAM,OAAO,GAAG,QAAQ,KAAK,EAAE,IAAI,GAAG,MAAM;AAE5C,QAAM,UAAU,KAAK,SAAS;AAC9B,QAAM,QAAQ,UAAU,KAAK,MAAM,GAAG,KAAK,IAAI;AAE/C,QAAM,QAA2B,MAAM,IAAI,CAAC,SAAS;AAAA,IACnD,IAAI,IAAI;AAAA,IACR,SAAS,IAAI;AAAA,IACb,UAAU,IAAI,aAAa;AAAA,IAC3B,OAAO,IAAI,QAAQ,KAAK,MAAM,IAAI,KAAK,IAAI;AAAA,IAC3C,QAAQ,IAAI;AAAA,IACZ,OAAO,IAAI;AAAA,IACX,YAAY,KAAK,MAAM,IAAI,UAAU;AAAA,EACvC,EAAE;AAEF,QAAM,SAAsB,EAAE,OAAO,MAAM;AAE3C,MAAI,SAAS;AACX,UAAM,OAAO,MAAM,MAAM,SAAS,CAAC;AACnC,WAAO,cAAc,GAAG,KAAK,UAAU,IAAI,KAAK,EAAE;AAAA,EACpD;AAEA,SAAO;AACT;;;ACxKO,SAAS,WACd,OACA,OACA,kBAA0B,IACd;AACZ,QAAM,UAAU,cAAc,OAAO,SAAS,SAAS;AACvD,QAAM,QAAQ,eAAe,OAAO,OAAO,OAAO;AAClD,QAAM,QAAQ,eAAe,OAAO,OAAO,SAAS,GAAG,EAAE,KAAK;AAC9D,QAAM,QAAQ,gBAAgB,OAAO,OAAO,OAAO,KAAK;AACxD,QAAM,KAAK,MAAM;AAGjB,MAAI,cAAc;AAClB,QAAM,cAAyB,CAAC;AAChC,MAAI,OAAO;AACT,UAAM,gBAAgB,GACnB;AAAA,MACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAMF,EACC,IAAI,KAAK;AAEZ,QAAI,cAAc,WAAW,GAAG;AAC9B,aAAO,EAAE,OAAO,CAAC,EAAE;AAAA,IACrB;AACA,kBAAc,gBAAgB,cAAc,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG,CAAC;AACpE,gBAAY,KAAK,GAAG,cAAc,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAAA,EACpD;AAGA,MAAI,QAAQ;AAAA;AAAA;AAAA,MAGR,WAAW;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAWf,QAAM,SAAoB,CAAC,SAAS,GAAG,WAAW;AAGlD,QAAM,cAAc,IAAI;AAAA,IACtB,KAAK,IAAI,IAAI,kBAAkB,KAAK;AAAA,EACtC,EAAE,YAAY;AAEd,WAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOT,SAAO,KAAK,OAAO,WAAW;AAG9B,MAAI,MAAM,QAAQ;AAChB,eAAW,CAAC,KAAK,KAAK,KAAK,OAAO,QAAQ,MAAM,MAAM,GAAG;AACvD,eAAS;AACT,aAAO,KAAK,KAAK,GAAG,IAAI,KAAwB;AAAA,IAClD;AAAA,EACF;AAIA,WAAS;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAOT,SAAO,KAAK,KAAK;AAEjB,QAAM,OAAO,GAAG,QAAQ,KAAK,EAAE,IAAI,GAAG,MAAM;AAE5C,QAAM,WAAW,KAAK,IAAI,CAAC,SAAS,EAAE,IAAI,EAAE;AAE5C,QAAM,UAA4B,SAAS,IAAI,CAAC,EAAE,IAAI,MAAM;AAC1D,UAAM,OAAO,QAAQ,IAAI,EAAE;AAC3B,UAAM,YAAY,aAAa,IAAI,EAAE;AAGrC,UAAM,YAAyD,CAAC;AAChE,eAAW,OAAO,WAAW;AAC3B,YAAM,UAAU,QAAQ,IAAI,EAAE;AAC9B,UAAI,WAAW,QAAQ,cAAc,SAAS,GAAG;AAC/C,kBAAU,KAAK,EAAE,SAAS,IAAI,IAAI,OAAO,QAAQ,cAAc,CAAC;AAAA,MAClE;AAAA,IACF;AAGA,UAAM,WAAW,aAAa,IAAI,IAAI,YAAY;AAClD,UAAM,gBAAgB,SACnB,IAAI,CAAC,SAAS;AACb,YAAM,UAAU,QAAQ,KAAK,OAAO;AACpC,UAAI,CAAC,WAAW,CAAC,QAAQ,SAAU,QAAO;AAC1C,aAAO;AAAA,QACL,IAAI,QAAQ;AAAA,QACZ,SAAS,QAAQ;AAAA,QACjB,UAAU,QAAQ;AAAA,MACpB;AAAA,IACF,CAAC,EACA,OAAO,OAAO;AAGjB,QAAI,OAAO;AACT,iBAAW;AAAA,QACT,SAAS,KAAK;AAAA,QACd;AAAA,QACA,YAAY;AAAA,UACV,aAAa;AAAA,UACb,cAAa,oBAAI,KAAK,GAAE,YAAY;AAAA,QACtC;AAAA,MACF,CAAC;AAAA,IACH;AAEA,WAAO;AAAA,MACL,MAAM,QAAQ,QAAQ,IAAI,EAAE,IAAK;AAAA,MACjC,WAAW,UAAU,IAAI,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,SAAS,EAAE,QAAQ,EAAE;AAAA,MAClE,eAAe;AAAA,QACb,MAAM,KAAK;AAAA,QACX;AAAA,MACF;AAAA,MACA;AAAA,IACF;AAAA,EACF,CAAC;AAGD,QAAM,YAAY,GACf;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMF,EACC,IAAI,SAAS,OAAO,WAAW;AAElC,QAAM,SAAqB,EAAE,OAAO,QAAQ;AAC5C,MAAI,UAAU,SAAS,GAAG;AACxB,WAAO,cAAc,UAAU,IAAI,CAAC,OAAO;AAAA,MACzC,IAAI,EAAE;AAAA,MACN,SAAS,EAAE;AAAA,MACX,YAAY,EAAE;AAAA,IAChB,EAAE;AAAA,EACJ;AAEA,SAAO;AACT;;;AC5JA,SAAS,uBAAuB,QAAgB,aAA8B;AAE5E,QAAM,KAAK,MAAM;AACjB,MAAI,UAAyB;AAE7B,SAAO,SAAS;AACd,QAAI,YAAY,OAAQ,QAAO;AAC/B,UAAM,MAAM,GACT,QAAQ,uCAAuC,EAC/C,IAAI,OAAO;AACd,cAAU,KAAK,UAAU;AAAA,EAC3B;AAEA,SAAO;AACT;AAEA,SAAS,kBAAkB,QAA0B;AACnD,QAAM,MAAgB,CAAC;AACvB,QAAM,QAAQ,CAAC,MAAM;AAErB,SAAO,MAAM,SAAS,GAAG;AACvB,UAAM,UAAU,MAAM,IAAI;AAC1B,UAAM,WAAW,YAAY,OAAO;AACpC,eAAW,SAAS,UAAU;AAC5B,UAAI,KAAK,MAAM,EAAE;AACjB,YAAM,KAAK,MAAM,EAAE;AAAA,IACrB;AAAA,EACF;AAEA,SAAO;AACT;AAEA,SAAS,sBAAsB,QAAgB,UAAwB;AACrE,QAAM,KAAK,MAAM;AACjB,KAAG,QAAQ,yCAAyC,EAAE,IAAI,UAAU,MAAM;AAC1E,QAAM,WAAW,GAAG,QAAQ,uCAAuC,EAAE,IAAI,MAAM;AAC/E,aAAW,SAAS,UAAU;AAC5B,0BAAsB,MAAM,IAAI,WAAW,CAAC;AAAA,EAC9C;AACF;AAEA,SAAS,WAAW,IAAY,OAAoD;AAClF,QAAM,KAAK,MAAM;AACjB,QAAM,OAAO,eAAe,GAAG,OAAO;AACtC,QAAM,YAAY,eAAe,GAAG,UAAU;AAE9C,MAAI,KAAK,YAAY,UAAU,SAAS;AACtC,UAAM,IAAI,YAAY,iBAAiB,sCAAsC,KAAK,OAAO,aAAQ,UAAU,OAAO,GAAG;AAAA,EACvH;AAEA,MAAI,uBAAuB,GAAG,SAAS,GAAG,UAAU,GAAG;AACrD,UAAM,IAAI;AAAA,MACR;AAAA,MACA,4BAA4B,GAAG,OAAO,0BAA0B,GAAG,UAAU;AAAA,IAC/E;AAAA,EACF;AAEA,QAAM,YAAY,KAAK;AACvB,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AACnC,KAAG,QAAQ,0DAA0D,EAAE;AAAA,IACrE,GAAG;AAAA,IACH;AAAA,IACA,GAAG;AAAA,EACL;AAGA,wBAAsB,GAAG,SAAS,UAAU,QAAQ,CAAC;AAErD,WAAS,GAAG,SAAS,OAAO,SAAS;AAAA,IACnC,EAAE,OAAO,UAAU,QAAQ,WAAW,OAAO,GAAG,WAAW;AAAA,EAC7D,CAAC;AAED,SAAO,EAAE,SAAS,GAAG,SAAS,QAAQ,eAAe,GAAG,UAAU,GAAG;AACvE;AAEA,SAAS,YAAY,IAAa,OAAoD;AACpF,QAAM,KAAK,MAAM;AACjB,QAAM,SAAS,eAAe,GAAG,MAAM;AACvC,QAAM,SAAS,eAAe,GAAG,MAAM;AAEvC,MAAI,OAAO,YAAY,OAAO,SAAS;AACrC,UAAM,IAAI,YAAY,iBAAiB,wCAAwC,OAAO,OAAO,aAAQ,OAAO,OAAO,GAAG;AAAA,EACxH;AAGA,QAAM,gBAAgB,GAAG,QAAQ,uCAAuC,EAAE,IAAI,GAAG,MAAM;AACvF,KAAG,QAAQ,8DAA8D,EAAE;AAAA,IACzE,GAAG;AAAA,KACH,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvB,GAAG;AAAA,EACL;AACA,aAAW,SAAS,eAAe;AACjC,0BAAsB,MAAM,IAAI,OAAO,QAAQ,CAAC;AAAA,EAClD;AAGA,QAAM,iBAA6B,CAAC,GAAG,OAAO,UAAU,GAAG,OAAO,QAAQ;AAC1E,KAAG,QAAQ,4DAA4D,EAAE;AAAA,IACvE,KAAK,UAAU,cAAc;AAAA,KAC7B,oBAAI,KAAK,GAAE,YAAY;AAAA,IACvB,GAAG;AAAA,EACL;AAGA,QAAM,iBAAiB,aAAa,GAAG,MAAM;AAC7C,QAAM,gBAAgB,WAAW,GAAG,MAAM;AAE1C,aAAW,QAAQ,gBAAgB;AAEjC,UAAM,WAAW,GACd;AAAA,MACC;AAAA,IACF,EACC,IAAI,GAAG,QAAQ,KAAK,SAAS,KAAK,IAAI;AAEzC,QAAI,CAAC,UAAU;AACb,SAAG;AAAA,QACD;AAAA,MACF,EAAE,IAAI,GAAG,QAAQ,KAAK,EAAE;AAAA,IAC1B,OAAO;AACL,SAAG,QAAQ,gCAAgC,EAAE,IAAI,KAAK,EAAE;AAAA,IAC1D;AAAA,EACF;AAEA,aAAW,QAAQ,eAAe;AAEhC,UAAM,WAAW,GACd;AAAA,MACC;AAAA,IACF,EACC,IAAI,KAAK,WAAW,GAAG,QAAQ,KAAK,IAAI;AAE3C,QAAI,CAAC,UAAU;AACb,SAAG;AAAA,QACD;AAAA,MACF,EAAE,IAAI,GAAG,QAAQ,KAAK,EAAE;AAAA,IAC1B,OAAO;AACL,SAAG,QAAQ,gCAAgC,EAAE,IAAI,KAAK,EAAE;AAAA,IAC1D;AAAA,EACF;AAGA,WAAS,GAAG,QAAQ,OAAO,UAAU;AAAA,IACnC,EAAE,OAAO,eAAe,QAAQ,MAAM,OAAO,GAAG,OAAO;AAAA,EACzD,CAAC;AAGD,KAAG,QAAQ,sCAAsC,EAAE,IAAI,GAAG,MAAM;AAChE,KAAG,QAAQ,sDAAsD,EAAE;AAAA,IACjE,GAAG;AAAA,IACH,GAAG;AAAA,EACL;AACA,KAAG,QAAQ,gCAAgC,EAAE,IAAI,GAAG,MAAM;AAE1D,SAAO,EAAE,SAAS,GAAG,QAAQ,QAAQ,UAAU,GAAG,MAAM,SAAS,GAAG,MAAM,GAAG;AAC/E;AAEA,SAAS,WAAW,IAAY,OAAoD;AAClF,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAGnC,QAAM,cAAc,kBAAkB,GAAG,OAAO;AAChD,QAAM,SAAS,CAAC,GAAG,SAAS,GAAG,WAAW;AAG1C,aAAW,MAAM,QAAQ;AACvB,UAAM,OAAO,QAAQ,EAAE;AACvB,QAAI,CAAC,QAAQ,KAAK,SAAU;AAE5B,eAAW;AAAA,MACT,SAAS;AAAA,MACT;AAAA,MACA,UAAU;AAAA,MACV,cAAc,CAAC,EAAE,MAAM,WAAW,KAAK,GAAG,OAAO,CAAC;AAAA,IACpD,CAAC;AAED,aAAS,IAAI,OAAO,WAAW;AAAA,MAC7B,EAAE,OAAO,YAAY,QAAQ,OAAO,OAAO,KAAK;AAAA,MAChD,EAAE,OAAO,UAAU,QAAQ,MAAM,OAAO,GAAG,OAAO;AAAA,IACpD,CAAC;AAAA,EACH;AAEA,SAAO;AAAA,IACL,SAAS,GAAG;AAAA,IACZ,QAAQ,WAAW,OAAO,MAAM,aAAa,GAAG,MAAM;AAAA,EACxD;AACF;AAEA,SAAS,aAAa,IAAc,OAAoD;AACtF,QAAM,KAAK,MAAM;AACjB,iBAAe,GAAG,OAAO;AAEzB,QAAM,cAAc,kBAAkB,GAAG,OAAO;AAChD,QAAM,SAAS,CAAC,GAAG,SAAS,GAAG,WAAW;AAC1C,QAAM,eAAe,OAAO,IAAI,MAAM,GAAG,EAAE,KAAK,GAAG;AAGnD,KAAG,QAAQ,wCAAwC,YAAY,GAAG,EAAE,IAAI,GAAG,MAAM;AACjF,KAAG,QAAQ,yCAAyC,YAAY,oBAAoB,YAAY,GAAG,EAAE,IAAI,GAAG,QAAQ,GAAG,MAAM;AAC7H,KAAG,QAAQ,kCAAkC,YAAY,GAAG,EAAE,IAAI,GAAG,MAAM;AAE3E,SAAO;AAAA,IACL,SAAS,GAAG;AAAA,IACZ,QAAQ,WAAW,OAAO,MAAM;AAAA,EAClC;AACF;AAEO,SAAS,kBACd,OACA,OACmB;AACnB,QAAM,aAAa,aAA4B,OAAO,YAAY,YAAY;AAE9E,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;AAC1C,UAAM,KAAK,WAAW,CAAC;AACvB,kBAAc,GAAG,IAAI,cAAc,CAAC,MAAM;AAC1C,QAAI,GAAG,OAAO,QAAQ;AACpB,oBAAe,GAAc,SAAS,cAAc,CAAC,WAAW;AAChE,oBAAe,GAAc,YAAY,cAAc,CAAC,cAAc;AAAA,IACxE,WAAW,GAAG,OAAO,SAAS;AAC5B,oBAAe,GAAe,QAAQ,cAAc,CAAC,UAAU;AAC/D,oBAAe,GAAe,QAAQ,cAAc,CAAC,UAAU;AAAA,IACjE,WAAW,GAAG,OAAO,QAAQ;AAC3B,oBAAe,GAAc,SAAS,cAAc,CAAC,WAAW;AAChE,oBAAe,GAAc,QAAQ,cAAc,CAAC,UAAU;AAAA,IAChE,WAAW,GAAG,OAAO,UAAU;AAC7B,oBAAe,GAAgB,SAAS,cAAc,CAAC,WAAW;AAAA,IACpE,OAAO;AACL,YAAM,IAAI,YAAY,cAAc,sBAAsB,GAAG,EAAE,EAAE;AAAA,IACnE;AAAA,EACF;AAEA,QAAM,KAAK,MAAM;AACjB,MAAI,UAAU;AACd,QAAM,UAAkE,CAAC;AACzE,MAAI,UAAyB;AAE7B,QAAM,cAAc,GAAG,YAAY,MAAM;AACvC,eAAW,MAAM,YAAY;AAC3B,UAAI;AAEJ,cAAQ,GAAG,IAAI;AAAA,QACb,KAAK;AACH,mBAAS,WAAW,IAAI,KAAK;AAC7B,oBAAU,QAAQ,GAAG,OAAO,GAAG,WAAW;AAC1C;AAAA,QACF,KAAK;AACH,mBAAS,YAAY,IAAI,KAAK;AAC9B,oBAAU,QAAQ,GAAG,MAAM,GAAG,WAAW;AACzC;AAAA,QACF,KAAK;AACH,mBAAS,WAAW,IAAI,KAAK;AAC7B,oBAAU,QAAQ,GAAG,OAAO,GAAG,WAAW;AAC1C;AAAA,QACF,KAAK;AACH,oBAAU,QAAQ,GAAG,OAAO,GAAG,WAAW;AAC1C,mBAAS,aAAa,IAAI,KAAK;AAC/B;AAAA,QACF;AACE,gBAAM,IAAI,MAAM,sBAAuB,GAAqB,EAAE,EAAE;AAAA,MACpE;AAEA,cAAQ,KAAK,EAAE,IAAI,GAAG,IAAI,GAAG,OAAO,CAAC;AACrC;AAAA,IACF;AAAA,EACF,CAAC;AAED,cAAY;AAEZ,QAAM,SAA4B,EAAE,SAAS,QAAQ;AAErD,MAAI,SAAS;AACX,UAAM,aAAa,oBAAoB,OAAO;AAC9C,QAAI,WAAW,SAAS,GAAG;AACzB,aAAO,mBAAmB;AAAA,IAC5B;AAAA,EACF;AAEA,SAAO;AACT;;;AC7SO,SAAS,cAAc,OAAoC;AAChE,QAAM,SAAS,cAAc,OAAO,SAAS,SAAS;AACtD,QAAM,QAAQ,eAAe,OAAO,OAAO,SAAS,GAAG,GAAG,KAAK;AAC/D,QAAM,SAAS,eAAe,OAAO,QAAQ,QAAQ;AAErD,iBAAe,MAAM;AAErB,QAAM,EAAE,QAAQ,YAAY,IAAI,UAAU,QAAQ,OAAO,MAAM;AAE/D,QAAM,SAAwB;AAAA,IAC5B,QAAQ,OAAO,IAAI,CAAC,OAAO;AAAA,MACzB,WAAW,EAAE;AAAA,MACb,OAAO,EAAE;AAAA,MACT,QAAQ,EAAE;AAAA,MACV,SAAS,EAAE;AAAA,IACb,EAAE;AAAA,EACJ;AAEA,MAAI,aAAa;AACf,WAAO,cAAc;AAAA,EACvB;AAEA,SAAO;AACT;;;ACsBO,SAAS,cAAc,OAAkG;AAC9H,QAAM,gBAAgB,eAAe,OAAO,gBAAgB,kBAAkB,GAAG,EAAE,KAAK;AACxF,QAAM,KAAK,MAAM;AAGjB,MAAI,UAAU,eAAe,OAAO,SAAS,SAAS;AACtD,MAAI,CAAC,SAAS;AACZ,UAAM,WAAW,aAAa;AAC9B,QAAI,SAAS,WAAW,GAAG;AACzB,aAAO;AAAA,QACL,UAAU,CAAC;AAAA,QACX,MAAM;AAAA,MACR;AAAA,IACF;AACA,QAAI,SAAS,WAAW,GAAG;AACzB,gBAAU,SAAS,CAAC,EAAE;AAAA,IACxB,OAAO;AACL,aAAO;AAAA,QACL;AAAA,QACA,MAAM,GAAG,SAAS,MAAM;AAAA,MAC1B;AAAA,IACF;AAAA,EACF;AAGA,QAAM,OAAO,eAAe,OAAO;AACnC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,YAAY,qBAAqB,sBAAsB,OAAO,EAAE;AAAA,EAC5E;AAGA,QAAM,UAAU,kBAAkB,OAAO;AAGzC,QAAM,cAAc,GACjB,QAAQ,8DAA8D,EACtE,IAAI,KAAK,EAAE;AAEd,QAAM,OAAO,YAAY,IAAI,CAAC,UAAU;AACtC,UAAM,gBAAgB,GACnB;AAAA,MACC;AAAA;AAAA;AAAA,IAGF,EACC,IAAI,MAAM,EAAE;AAOf,WAAO;AAAA,MACL,IAAI,MAAM;AAAA,MACV,SAAS,MAAM;AAAA,MACf,UAAU,MAAM,aAAa;AAAA,MAC7B,WAAW,MAAM;AAAA,MACjB,UAAU,cAAc,IAAI,CAAC,QAAQ;AAAA,QACnC,IAAI,GAAG;AAAA,QACP,SAAS,GAAG;AAAA,QACZ,UAAU,GAAG,aAAa;AAAA,QAC1B,aAAa,GAAG;AAAA,MAClB,EAAE;AAAA,IACJ;AAAA,EACF,CAAC;AAGD,QAAM,WAAW,GACd,QAAQ,iGAAiG,EACzG,IAAI,OAAO;AAEd,QAAM,cAAgD,CAAC;AACvD,aAAW,QAAQ,UAAU;AAC3B,UAAM,WAAuB,KAAK,MAAM,KAAK,QAAQ;AACrD,eAAW,MAAM,UAAU;AACzB,kBAAY,KAAK;AAAA,QACf,SAAS,KAAK;AAAA,QACd,cAAc,KAAK;AAAA,QACnB,MAAM,GAAG;AAAA,QACT,KAAK,GAAG;AAAA,QACR,OAAO,GAAG;AAAA,QACV,WAAW,GAAG;AAAA,MAChB,CAAC;AAAA,IACH;AAAA,EACF;AACA,cAAY,KAAK,CAAC,GAAG,MAAM,EAAE,UAAU,cAAc,EAAE,SAAS,CAAC;AACjE,QAAM,kBAAkB,YAAY,MAAM,GAAG,aAAa;AAG1D,QAAM,WAAW,GACd,QAAQ,6EAA6E,EACrF,IAAI,OAAO;AAEd,QAAM,UAAU,oBAAI,IAAY;AAChC,aAAW,OAAO,UAAU;AAC1B,UAAM,QAAkB,KAAK,MAAM,IAAI,aAAa;AACpD,eAAW,QAAQ,OAAO;AACxB,cAAQ,IAAI,IAAI;AAAA,IAClB;AAAA,EACF;AACA,QAAM,gBAAgB,CAAC,GAAG,OAAO,EAAE,KAAK;AAGxC,QAAM,gBAAgB,GACnB,QAAQ,2FAA2F,EACnG,IAAI,OAAO;AAGd,QAAM,iBAAiB,GACpB;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAeF,EACC,IAAI,OAAO;AAEd,QAAM,aAAa,eAAe,IAAI,CAAC,SAAS;AAAA,IAC9C,IAAI,IAAI;AAAA,IACR,SAAS,IAAI;AAAA,IACb,YAAY,KAAK,MAAM,IAAI,UAAU;AAAA,EACvC,EAAE;AAGF,QAAM,YAAY,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,KAAK,GAAI,EAAE,YAAY;AACzE,QAAM,uBAAuB,GAC1B;AAAA,IACC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAMF,EACC,IAAI,SAAS,SAAS;AAEzB,QAAM,oBAAoB,qBAAqB,IAAI,CAAC,SAAS;AAAA,IAC3D,IAAI,IAAI;AAAA,IACR,SAAS,IAAI;AAAA,IACb,aAAa,IAAI;AAAA,IACjB,OAAO,IAAI,cAAc;AAAA,EAC3B,EAAE;AAGF,QAAM,kBAAkB,GACrB,QAAQ,6DAA6D,EACrE,IAAI,OAAO;AACd,QAAM,gBAAgB,gBAAgB;AAGtC,MAAI;AACJ,MAAI,KAAK,cAAc,WAAW;AAChC,WAAO;AAAA,EACT,WAAW,WAAW,SAAS,GAAG;AAChC,UAAM,aAAa,kBAAkB,SAAS,IAC1C,IAAI,kBAAkB,MAAM,gCAC5B;AACJ,WAAO,GAAG,WAAW,MAAM,6BAA6B,UAAU,+BAA+B,OAAO;AAAA,EAC1G,WAAW,QAAQ,aAAa,KAAK,QAAQ,eAAe,GAAG;AAC7D,WAAO;AAAA,EACT,WAAW,QAAQ,SAAS,KAAK,KAAK,cAAc,WAAW;AAC7D,WAAO;AAAA,EACT;AAEA,SAAO;AAAA,IACL;AAAA,IACA,MAAM,KAAK;AAAA,IACX,WAAW,KAAK;AAAA,IAChB;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,EACF;AACF;;;AC9NA,SAAS,UACP,MACA,cACA,UACA,OAC+D;AAC/D,QAAM;AACN,MAAI,KAAK,SAAU,OAAM;AAEzB,QAAM,WAAW,YAAY,KAAK,EAAE;AACpC,QAAM,WAAqB;AAAA,IACzB,IAAI,KAAK;AAAA,IACT,SAAS,KAAK;AAAA,IACd,UAAU,KAAK;AAAA,IACf,YAAY,KAAK;AAAA,EACnB;AAEA,MAAI,WAAW;AACf,MAAI,cAAc,KAAK,WAAW,IAAI;AAEtC,MAAI,SAAS,WAAW,EAAG,QAAO,EAAE,UAAU,UAAU,YAAY;AAEpE,MAAI,eAAe,UAAU;AAC3B,aAAS,WAAW,CAAC;AACrB,eAAW,SAAS,UAAU;AAC5B,YAAM,SAAS,UAAU,OAAO,eAAe,GAAG,UAAU,KAAK;AACjE,eAAS,SAAS,KAAK,OAAO,QAAQ;AACtC,kBAAY,OAAO;AACnB,qBAAe,OAAO;AAAA,IACxB;AAAA,EACF,OAAO;AACL,aAAS,cAAc,SAAS;AAEhC,UAAM,WAAW,mBAAmB,KAAK,EAAE;AAC3C,eAAW,SAAS;AACpB,kBAAc,SAAS;AAAA,EACzB;AAEA,WAAS,WAAW,EAAE,UAAU,aAAa,OAAO,SAAS;AAC7D,SAAO,EAAE,UAAU,UAAU,YAAY;AAC3C;AAEO,SAAS,WAAW,OAA8B;AACvD,QAAM,UAAU,cAAc,OAAO,SAAS,SAAS;AACvD,QAAM,QAAQ,eAAe,OAAO,OAAO,SAAS,GAAG,EAAE,KAAK;AAE9D,QAAM,OAAO,eAAe,OAAO;AACnC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,YAAY,qBAAqB,sBAAsB,OAAO,EAAE;AAAA,EAC5E;AAEA,QAAM,QAAQ,EAAE,OAAO,GAAG,UAAU,EAAE;AACtC,QAAM,EAAE,SAAS,IAAI,UAAU,MAAM,GAAG,OAAO,KAAK;AAEpD,SAAO;AAAA,IACL;AAAA,IACA,MAAM;AAAA,IACN,OAAO;AAAA,MACL,OAAO,MAAM;AAAA,MACb,UAAU,MAAM;AAAA,MAChB,YAAY,MAAM,QAAQ,MAAM;AAAA,IAClC;AAAA,EACF;AACF;;;AC/FA,SAAS,UAAAC,eAAc;AAyBhB,SAAS,qBAAqB,OAA4B,OAAe;AAC9E,QAAM,UAAU,cAAc,MAAM,SAAS,SAAS;AACtD,QAAM,MAAM,cAAc,MAAM,KAAK,KAAK;AAC1C,QAAM,UAAU,cAAc,MAAM,SAAS,SAAS;AAEtD,QAAM,OAAO,eAAe,OAAO;AACnC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,YAAY,aAAa,YAAY,OAAO,aAAa;AAAA,EACrE;AAEA,QAAM,KAAK,MAAM;AACjB,QAAM,OAAM,oBAAI,KAAK,GAAE,YAAY;AAEnC,QAAM,WAAW,GACd,QAAQ,wDAAwD,EAChE,IAAI,SAAS,GAAG;AAEnB,MAAI,UAAU;AACZ,OAAG;AAAA,MACD;AAAA,IACF,EAAE,IAAI,SAAS,KAAK,SAAS,EAAE;AAC/B,WAAO,EAAE,KAAK,QAAQ,UAAU;AAAA,EAClC,OAAO;AACL,UAAM,KAAKC,QAAO;AAClB,OAAG;AAAA,MACD;AAAA,IACF,EAAE,IAAI,IAAI,SAAS,KAAK,SAAS,OAAO,KAAK,GAAG;AAChD,WAAO,EAAE,KAAK,QAAQ,UAAU;AAAA,EAClC;AACF;AASO,SAAS,oBAAoB,OAA2B;AAC7D,QAAM,UAAU,cAAc,MAAM,SAAS,SAAS;AAEtD,QAAM,OAAO,eAAe,OAAO;AACnC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,YAAY,aAAa,YAAY,OAAO,aAAa;AAAA,EACrE;AAEA,QAAM,KAAK,MAAM;AAEjB,MAAI,MAAM,KAAK;AACb,UAAM,MAAM,GACT,QAAQ,uDAAuD,EAC/D,IAAI,SAAS,MAAM,GAAG;AAEzB,QAAI,CAAC,KAAK;AACR,YAAM,IAAI,YAAY,aAAa,oBAAoB,MAAM,GAAG,2BAA2B,OAAO,GAAG;AAAA,IACvG;AAEA,WAAO;AAAA,MACL,KAAK,IAAI;AAAA,MACT,SAAS,IAAI;AAAA,MACb,YAAY,IAAI;AAAA,MAChB,YAAY,IAAI;AAAA,IAClB;AAAA,EACF;AAGA,QAAM,OAAO,GACV,QAAQ,uGAAuG,EAC/G,IAAI,OAAO;AAEd,SAAO,EAAE,SAAS,KAAK;AACzB;AASO,SAAS,sBAAsB,OAA6B;AACjE,QAAM,UAAU,cAAc,MAAM,SAAS,SAAS;AACtD,QAAM,MAAM,cAAc,MAAM,KAAK,KAAK;AAE1C,QAAM,OAAO,eAAe,OAAO;AACnC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,YAAY,aAAa,YAAY,OAAO,aAAa;AAAA,EACrE;AAEA,QAAM,KAAK,MAAM;AACjB,QAAM,SAAS,GACZ,QAAQ,qDAAqD,EAC7D,IAAI,SAAS,GAAG;AAEnB,MAAI,OAAO,YAAY,GAAG;AACxB,UAAM,IAAI,YAAY,aAAa,oBAAoB,GAAG,2BAA2B,OAAO,GAAG;AAAA,EACjG;AAEA,SAAO,EAAE,KAAK,QAAQ,UAAU;AAClC;AASO,SAAS,sBAAsB,OAA6B;AACjE,QAAM,UAAU,cAAc,MAAM,SAAS,SAAS;AACtD,QAAM,QAAQ,cAAc,MAAM,OAAO,OAAO;AAEhD,QAAM,OAAO,eAAe,OAAO;AACnC,MAAI,CAAC,MAAM;AACT,UAAM,IAAI,YAAY,aAAa,YAAY,OAAO,aAAa;AAAA,EACrE;AAEA,QAAM,KAAK,MAAM;AACjB,QAAM,UAAU,IAAI,KAAK;AAEzB,QAAM,OAAO,GACV;AAAA,IACC;AAAA,EACF,EACC,IAAI,SAAS,SAAS,OAAO;AAEhC,SAAO,EAAE,SAAS,MAAM,MAAM;AAChC;;;ACjJA,IAAM,cAAc;AAAA,EAClB,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,sBAAsB;AAAA,EACtB,cAAc;AAChB;AAMO,SAAS,eAAe,MAAY,SAAiB,QAAsB;AAChF,MAAI,SAAS,MAAO;AAEpB,QAAM,KAAK,MAAM;AACjB,QAAM,EAAE,MAAM,IAAI,GACf,QAAQ,uDAAuD,EAC/D,IAAI,OAAO;AAEd,MAAI,QAAQ,SAAS,YAAY,oBAAoB;AACnD,UAAM,IAAI;AAAA,MACR;AAAA,MACA,2BAA2B,YAAY,kBAAkB,gCAC7C,KAAK,aAAa,MAAM;AAAA,IACtC;AAAA,EACF;AACF;AAMO,SAAS,kBAAkB,MAAkB;AAClD,MAAI,SAAS,MAAO;AAEpB,QAAM,KAAK,MAAM;AACjB,QAAM,EAAE,MAAM,IAAI,GACf,QAAQ,0DAA0D,EAClE,IAAI;AAEP,MAAI,SAAS,YAAY,aAAa;AACpC,UAAM,IAAI;AAAA,MACR;AAAA,MACA,2BAA2B,YAAY,WAAW;AAAA,IAEpD;AAAA,EACF;AACF;AAKO,SAAS,iBAAiB,MAAY,WAA4B;AACvE,QAAM,MAAM,SAAS,QAAS,aAAa,KAAM,YAAY;AAC7D,SAAO,KAAK,IAAI,aAAa,KAAK,SAAS,QAAQ,KAAK,YAAY,oBAAoB;AAC1F;AAMO,SAAS,mBAAmB,OAAmB;AAEpD;AACF;AAMO,SAAS,WAAW,OAAa,OAAoC;AAC1E,SAAO;AACT;;;AdpDA,SAAS,kBAAkB;AAC3B,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,eAAe;AACxB,SAAS,MAAM,SAAS,eAAe;AACvC,SAAS,qBAAqB;AAG9B,IAAM,iBAAiB,QAAQ,IAAI,eAAe;AAClD,IAAM,YAAY,SAAS,QAAQ,IAAI,mBAAmB,MAAM,EAAE;AAElE,SAAS,gBAAwB;AAC/B,QAAM,aAAa,QAAQ,GAAG;AAC9B,QAAM,OAAO,WAAW,QAAQ,EAAE,OAAO,UAAU,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAE;AAC9E,QAAM,MAAM,KAAK,QAAQ,GAAG,UAAU,MAAM,IAAI;AAChD,YAAU,KAAK,EAAE,WAAW,KAAK,CAAC;AAClC,SAAO,KAAK,KAAK,UAAU;AAC7B;AAEA,IAAM,UAAU,QAAQ,IAAI,YAAY,cAAc;AAGtD,IAAM,WAAW;AACjB,IAAI,cAAc;AAClB,IAAI;AACF,QAAM,YAAY,QAAQ,cAAc,YAAY,GAAG,CAAC;AACxD,QAAM,MAAM,KAAK,MAAM,aAAa,KAAK,WAAW,MAAM,cAAc,GAAG,OAAO,CAAC;AACnF,gBAAc,IAAI;AACpB,QAAQ;AAAC;AAGT,IAAI,gBAA+B,YAAY,WAAW;AAG1D,IAAI,gBAA+B;AAEnC,eAAe,iBAAgC;AAC7C,MAAI;AACF,UAAM,MAAM,MAAM,MAAM,8BAA8B,QAAQ,SAAS;AACvE,QAAI,CAAC,IAAI,GAAI;AACb,UAAM,OAAO,MAAM,IAAI,KAAK;AAC5B,QAAI,KAAK,YAAY,aAAa;AAChC,sBAAgB,6BAA6B,WAAW,WAAM,KAAK,OAAO;AAAA,IAC5E;AAAA,EACF,QAAQ;AAAA,EAAC;AACX;AAGA,SAAS,0BAAyC;AAChD,MAAI;AACF,UAAM,cAAc,QAAQ,GAAG;AAC/B,UAAM,YAAY,KAAK,aAAa,WAAW,UAAU,UAAU;AACnE,UAAM,SAAS,kBAAkB,WAAW,EAAE;AAE9C,QAAI,WAAW,SAAS,GAAG;AACzB,YAAM,UAAU,aAAa,WAAW,OAAO;AAC/C,UAAI,YAAY,OAAQ,QAAO;AAE/B,YAAM,QAAQ,QAAQ,MAAM,yCAAyC;AACrE,YAAM,aAAa,QAAQ,CAAC,KAAK;AACjC,oBAAc,WAAW,QAAQ,OAAO;AACxC,aAAO,4CAA4C,UAAU,WAAM,WAAW;AAAA,IAChF,OAAO;AACL,gBAAU,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD,oBAAc,WAAW,QAAQ,OAAO;AACxC,aAAO;AAAA,IACT;AAAA,EACF,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAGA,IAAM,QAAQ;AAAA,EACZ;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS;AAAA,UACP,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,gBAAgB;AAAA,UACd,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,YACL,MAAM;AAAA,YACN,YAAY;AAAA,cACV,KAAK;AAAA,gBACH,MAAM;AAAA,gBACN,aAAa;AAAA,cACf;AAAA,cACA,YAAY;AAAA,gBACV,MAAM;AAAA,gBACN,aACE;AAAA,cACJ;AAAA,cACA,SAAS,EAAE,MAAM,SAAS;AAAA,cAC1B,eAAe;AAAA,gBACb,MAAM;AAAA,gBACN,OAAO,EAAE,MAAM,SAAS;AAAA,gBACxB,aAAa;AAAA,cACf;AAAA,cACA,YAAY;AAAA,gBACV,MAAM;AAAA,gBACN,OAAO,EAAE,MAAM,SAAS;AAAA,gBACxB,aACE;AAAA,cACJ;AAAA,cACA,YAAY;AAAA,gBACV,MAAM;AAAA,gBACN,aAAa;AAAA,cACf;AAAA,YACF;AAAA,YACA,UAAU,CAAC,OAAO,SAAS;AAAA,UAC7B;AAAA,UACA,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,kDAAkD;AAAA,QAC1F,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,QACA,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aACE;AAAA,QACJ;AAAA,MACF;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,qBAAqB;AAAA,QAC7D,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS;AAAA,UACP,MAAM;AAAA,UACN,OAAO;AAAA,YACL,MAAM;AAAA,YACN,YAAY;AAAA,cACV,SAAS,EAAE,MAAM,SAAS;AAAA,cAC1B,cAAc,EAAE,MAAM,UAAU,aAAa,uHAAuH;AAAA,cACpK,UAAU,EAAE,MAAM,UAAU;AAAA,cAC5B,iBAAiB,EAAE,MAAM,UAAU,aAAa,+FAA+F;AAAA,cAC/I,WAAW,EAAE,MAAM,UAAU,aAAa,mGAAmG;AAAA,cAC7I,SAAS,EAAE,MAAM,WAAW,aAAa,sJAAsJ;AAAA,cAC/L,gBAAgB,EAAE,MAAM,UAAU,aAAa,kEAAkE;AAAA,cACjH,OAAO,EAAE,aAAa,gCAAgC;AAAA,cACtD,SAAS,EAAE,MAAM,SAAS;AAAA,cAC1B,YAAY;AAAA,gBACV,MAAM;AAAA,gBACN,aACE;AAAA,cACJ;AAAA,cACA,mBAAmB;AAAA,gBACjB,MAAM;AAAA,gBACN,OAAO,EAAE,MAAM,SAAS;AAAA,gBACxB,aAAa;AAAA,cACf;AAAA,cACA,sBAAsB;AAAA,gBACpB,MAAM;AAAA,gBACN,OAAO,EAAE,MAAM,SAAS;AAAA,cAC1B;AAAA,cACA,cAAc;AAAA,gBACZ,MAAM;AAAA,gBACN,aAAa;AAAA,gBACb,OAAO;AAAA,kBACL,MAAM;AAAA,kBACN,YAAY;AAAA,oBACV,MAAM,EAAE,MAAM,UAAU,aAAa,4CAA4C;AAAA,oBACjF,KAAK,EAAE,MAAM,UAAU,aAAa,2EAAsE;AAAA,kBAC5G;AAAA,kBACA,UAAU,CAAC,QAAQ,KAAK;AAAA,gBAC1B;AAAA,cACF;AAAA,YACF;AAAA,YACA,UAAU,CAAC,SAAS;AAAA,UACtB;AAAA,QACF;AAAA,MACF;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,OAAO;AAAA,UACL,MAAM;AAAA,UACN,OAAO;AAAA,YACL,MAAM;AAAA,YACN,YAAY;AAAA,cACV,MAAM,EAAE,MAAM,UAAU,aAAa,iBAAiB;AAAA,cACtD,IAAI,EAAE,MAAM,UAAU,aAAa,iBAAiB;AAAA,cACpD,MAAM;AAAA,gBACJ,MAAM;AAAA,gBACN,aAAa;AAAA,cACf;AAAA,cACA,QAAQ;AAAA,gBACN,MAAM;AAAA,gBACN,aAAa;AAAA,cACf;AAAA,YACF;AAAA,YACA,UAAU,CAAC,QAAQ,MAAM,MAAM;AAAA,UACjC;AAAA,QACF;AAAA,MACF;AAAA,MACA,UAAU,CAAC,OAAO;AAAA,IACpB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,kDAAkD;AAAA,QAC1F,QAAQ;AAAA,UACN,MAAM;AAAA,UACN,YAAY;AAAA,YACV,UAAU,EAAE,MAAM,UAAU;AAAA,YAC5B,YAAY,EAAE,MAAM,SAAS;AAAA,YAC7B,MAAM,EAAE,MAAM,UAAU,aAAa,6BAA6B;AAAA,YAClE,UAAU;AAAA,cACR,MAAM;AAAA,cACN,aAAa;AAAA,YACf;AAAA,YACA,mBAAmB,EAAE,MAAM,SAAS;AAAA,YACpC,SAAS,EAAE,MAAM,UAAU;AAAA,YAC3B,eAAe,EAAE,MAAM,UAAU;AAAA,YACjC,YAAY,EAAE,MAAM,UAAU;AAAA,YAC9B,YAAY;AAAA,cACV,MAAM,CAAC,UAAU,MAAM;AAAA,cACvB,aAAa;AAAA,YACf;AAAA,UACF;AAAA,QACF;AAAA,QACA,MAAM;AAAA,UACJ,MAAM;AAAA,UACN,MAAM,CAAC,aAAa,SAAS,UAAU,SAAS;AAAA,QAClD;AAAA,QACA,OAAO,EAAE,MAAM,UAAU,aAAa,oCAAoC;AAAA,QAC1E,QAAQ,EAAE,MAAM,UAAU,aAAa,oBAAoB;AAAA,MAC7D;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,YAAY;AAAA,UACV,MAAM;AAAA,UACN,OAAO;AAAA,YACL,MAAM;AAAA,YACN,YAAY;AAAA,cACV,IAAI;AAAA,gBACF,MAAM;AAAA,gBACN,MAAM,CAAC,QAAQ,SAAS,QAAQ,QAAQ;AAAA,cAC1C;AAAA,cACA,SAAS,EAAE,MAAM,UAAU,aAAa,oBAAoB;AAAA,cAC5D,YAAY,EAAE,MAAM,UAAU,aAAa,WAAW;AAAA,cACtD,QAAQ,EAAE,MAAM,UAAU,aAAa,4BAA4B;AAAA,cACnE,QAAQ;AAAA,gBACN,MAAM;AAAA,gBACN,aAAa;AAAA,cACf;AAAA,cACA,QAAQ,EAAE,MAAM,UAAU,aAAa,gBAAgB;AAAA,YACzD;AAAA,YACA,UAAU,CAAC,IAAI;AAAA,UACjB;AAAA,QACF;AAAA,MACF;AAAA,MACA,UAAU,CAAC,YAAY;AAAA,IACzB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,SAAS;AAAA,QAC1B,OAAO,EAAE,MAAM,UAAU,aAAa,0BAA0B;AAAA,QAChE,QAAQ,EAAE,MAAM,UAAU,aAAa,oBAAoB;AAAA,MAC7D;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,kGAAkG;AAAA,QAC1I,gBAAgB;AAAA,UACd,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,mCAAmC;AAAA,QAC3E,OAAO;AAAA,UACL,MAAM;AAAA,UACN,aAAa;AAAA,QACf;AAAA,MACF;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY,CAAC;AAAA,IACf;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,eAAe;AAAA,QACvD,KAAK,EAAE,MAAM,UAAU,aAAa,wEAAwE;AAAA,QAC5G,SAAS,EAAE,MAAM,UAAU,aAAa,yBAAyB;AAAA,MACnE;AAAA,MACA,UAAU,CAAC,WAAW,OAAO,SAAS;AAAA,IACxC;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,eAAe;AAAA,QACvD,KAAK,EAAE,MAAM,UAAU,aAAa,yCAAyC;AAAA,MAC/E;AAAA,MACA,UAAU,CAAC,SAAS;AAAA,IACtB;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,eAAe;AAAA,QACvD,KAAK,EAAE,MAAM,UAAU,aAAa,gCAAgC;AAAA,MACtE;AAAA,MACA,UAAU,CAAC,WAAW,KAAK;AAAA,IAC7B;AAAA,EACF;AAAA,EACA;AAAA,IACE,MAAM;AAAA,IACN,aACE;AAAA,IACF,aAAa;AAAA,MACX,MAAM;AAAA,MACN,YAAY;AAAA,QACV,SAAS,EAAE,MAAM,UAAU,aAAa,eAAe;AAAA,QACvD,OAAO,EAAE,MAAM,UAAU,aAAa,gBAAgB;AAAA,MACxD;AAAA,MACA,UAAU,CAAC,WAAW,OAAO;AAAA,IAC/B;AAAA,EACF;AACF;AAEA,eAAsB,cAA6B;AAEjD,YAAU,OAAO;AAGjB,QAAM,OAAa,eAAe,OAAO;AAEzC,QAAM,SAAS,IAAI;AAAA,IACjB,EAAE,MAAM,SAAS,SAAS,YAAY;AAAA,IACtC,EAAE,cAAc,EAAE,OAAO,CAAC,GAAG,WAAW,CAAC,EAAE,EAAE;AAAA,EAC/C;AAGA,MAAI,QAAQ,IAAI,uBAAuB,KAAK;AAC1C,mBAAe;AAAA,EACjB;AAGA,SAAO,kBAAkB,wBAAwB,aAAa;AAAA,IAC5D,OAAO;AAAA,EACT,EAAE;AAGF,SAAO,kBAAkB,uBAAuB,OAAO,YAAY;AACjE,UAAM,EAAE,MAAM,WAAW,KAAK,IAAI,QAAQ;AAE1C,QAAI;AACF,UAAI;AAEJ,cAAQ,MAAM;AAAA,QACZ,KAAK,cAAc;AACjB,gBAAM,WAAW;AAEjB,cAAI,UAAU,SAAS;AACrB,kBAAM,EAAE,gBAAAC,gBAAe,IAAI,MAAM,OAAO,qBAAY;AACpD,gBAAI,CAACA,gBAAe,SAAS,OAAO,GAAG;AACrC,gCAAkB,IAAI;AAAA,YACxB;AAAA,UACF;AACA,mBAAS,WAAW,UAAU,cAAc;AAC5C;AAAA,QACF;AAAA,QAEA,KAAK,cAAc;AACjB,gBAAM,WAAW;AAEjB,cAAI,UAAU,OAAO,SAAS,GAAG;AAE/B,kBAAM,EAAE,SAAAC,SAAQ,IAAI,MAAM,OAAO,qBAAY;AAC7C,kBAAM,cAAc,SAAS,MAAM,CAAC,GAAG;AACvC,gBAAI,eAAe,OAAO,gBAAgB,YAAY,CAAC,SAAS,MAAM,KAAK,CAAC,MAAW,EAAE,QAAQ,WAAW,GAAG;AAC7G,oBAAM,aAAaA,SAAQ,WAAW;AACtC,kBAAI,YAAY;AACd,+BAAe,MAAM,WAAW,SAAS,SAAS,MAAM,MAAM;AAAA,cAChE;AAAA,YACF;AAAA,UACF;AACA,mBAAS,WAAW,UAAU,cAAc;AAC5C;AAAA,QACF;AAAA,QAEA,KAAK,cAAc;AACjB,gBAAM,WAAW;AAEjB,cAAI,UAAU,OAAO;AACnB,qBAAS,QAAQ,WAAW,MAAM,SAAS,KAAK;AAAA,UAClD;AACA,mBAAS,WAAW,UAAU,gBAAgB,SAAS;AACvD;AAAA,QACF;AAAA,QAEA,KAAK;AACH,mBAAS,cAAc,IAAW;AAClC;AAAA,QAEF,KAAK;AACH,mBAAS,aAAa,MAAa,cAAc;AACjD;AAAA,QAEF,KAAK;AACH,mBAAS,cAAc,MAAa,cAAc;AAClD;AAAA,QAEF,KAAK;AACH,mBAAS,YAAY,IAAW;AAChC;AAAA,QAEF,KAAK;AACH,mBAAS,kBAAkB,MAAa,cAAc;AACtD;AAAA,QAEF,KAAK;AACH,mBAAS,cAAc,IAAW;AAClC;AAAA,QAEF,KAAK,iBAAiB;AACpB,gBAAM,cAAc;AAEpB,sBAAY,iBAAiB,iBAAiB,MAAM,aAAa,cAAc;AAC/E,mBAAS,cAAc,WAAW;AAClC;AAAA,QACF;AAAA,QAEA,KAAK;AACH,mBAAS,WAAW,IAAW;AAC/B;AAAA,QAEF,KAAK;AACH,mBAAS,kBAAkB,WAAW;AACtC;AAAA,QAEF,KAAK;AACH,6BAAmB,IAAI;AACvB,mBAAS,qBAAqB,MAAa,cAAc;AACzD;AAAA,QAEF,KAAK;AACH,6BAAmB,IAAI;AACvB,mBAAS,oBAAoB,IAAW;AACxC;AAAA,QAEF,KAAK;AACH,6BAAmB,IAAI;AACvB,mBAAS,sBAAsB,IAAW;AAC1C;AAAA,QAEF,KAAK;AACH,6BAAmB,IAAI;AACvB,mBAAS,sBAAsB,IAAW;AAC1C;AAAA,QAEF;AACE,iBAAO;AAAA,YACL,SAAS;AAAA,cACP,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,EAAE,OAAO,iBAAiB,IAAI,GAAG,CAAC,EAAE;AAAA,YACpF;AAAA,YACA,SAAS;AAAA,UACX;AAAA,MACJ;AAEA,YAAM,UAAiD;AAAA,QACrD,EAAE,MAAM,QAAiB,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE;AAAA,MACjE;AACA,UAAI,eAAe;AACjB,cAAM,YAAY,wBAAwB;AAC1C,cAAM,cAAc,CAAC,aAAa;AAClC,YAAI,UAAW,aAAY,KAAK,SAAS;AACzC,YAAI,cAAe,aAAY,KAAK,aAAa;AACjD,gBAAQ,KAAK,EAAE,MAAM,QAAiB,MAAM,YAAY,KAAK,IAAI,EAAE,CAAC;AACpE,wBAAgB;AAChB,wBAAgB;AAAA,MAClB;AACA,aAAO,EAAE,QAAQ;AAAA,IACnB,SAAS,OAAO;AACd,YAAM,UACJ,iBAAiB,QAAQ,MAAM,UAAU,OAAO,KAAK;AACvD,YAAM,OACJ,iBAAiB,kBACb,qBACA,iBAAiB,cACd,MAAsB,OACvB;AACR,aAAO;AAAA,QACL,SAAS;AAAA,UACP;AAAA,YACE,MAAM;AAAA,YACN,MAAM,KAAK,UAAU,EAAE,OAAO,SAAS,KAAK,CAAC;AAAA,UAC/C;AAAA,QACF;AAAA,QACA,SAAS;AAAA,MACX;AAAA,IACF;AAAA,EACF,CAAC;AAKD,SAAO,kBAAkB,oCAAoC,aAAa;AAAA,IACxE,mBAAmB;AAAA,MACjB;AAAA,QACE,aAAa;AAAA,QACb,MAAM;AAAA,QACN,aAAa;AAAA,QACb,UAAU;AAAA,MACZ;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,MAAM;AAAA,QACN,aAAa;AAAA,QACb,UAAU;AAAA,MACZ;AAAA,MACA;AAAA,QACE,aAAa;AAAA,QACb,MAAM;AAAA,QACN,aAAa;AAAA,QACb,UAAU;AAAA,MACZ;AAAA,IACF;AAAA,EACF,EAAE;AAGF,SAAO,kBAAkB,4BAA4B,YAAY;AAC/D,QAAI;AACF,YAAM,EAAE,cAAAC,cAAa,IAAI,MAAM,OAAO,qBAAY;AAClD,YAAM,WAAWA,cAAa;AAC9B,YAAM,YAAY,SAAS,QAAQ,CAAC,MAAM;AAAA,QACxC;AAAA,UACE,KAAK,WAAW,EAAE,OAAO;AAAA,UACzB,MAAM,GAAG,EAAE,OAAO;AAAA,UAClB,aAAa,cAAc,EAAE,KAAK,WAAW,EAAE,QAAQ;AAAA,UACvD,UAAU;AAAA,QACZ;AAAA,QACA;AAAA,UACE,KAAK,WAAW,EAAE,OAAO;AAAA,UACzB,MAAM,GAAG,EAAE,OAAO;AAAA,UAClB,aAAa,yBAAyB,EAAE,OAAO;AAAA,UAC/C,UAAU;AAAA,QACZ;AAAA,MACF,CAAC;AACD,aAAO,EAAE,UAAU;AAAA,IACrB,QAAQ;AACN,aAAO,EAAE,WAAW,CAAC,EAAE;AAAA,IACzB;AAAA,EACF,CAAC;AAGD,SAAO,kBAAkB,2BAA2B,OAAO,YAAY;AACrE,UAAM,MAAM,QAAQ,OAAO;AAC3B,UAAM,QAAQ,IAAI,MAAM,2BAA2B;AACnD,QAAI,CAAC,OAAO;AACV,YAAM,IAAI,MAAM,yBAAyB,GAAG,EAAE;AAAA,IAChD;AAEA,UAAM,CAAC,EAAE,SAAS,IAAI,IAAI;AAE1B,QAAI,SAAS,QAAQ;AACnB,YAAM,SAAS,WAAW,EAAE,QAAQ,CAAC;AACrC,aAAO;AAAA,QACL,UAAU,CAAC,EAAE,KAAK,UAAU,oBAAoB,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,CAAC;AAAA,MACzF;AAAA,IACF;AAEA,QAAI,SAAS,aAAa;AACxB,YAAM,SAAS,oBAAoB,EAAE,QAAQ,CAAC;AAC9C,aAAO;AAAA,QACL,UAAU,CAAC,EAAE,KAAK,UAAU,oBAAoB,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,CAAC;AAAA,MACzF;AAAA,IACF;AAEA,UAAM,iBAAiB,KAAK,MAAM,mBAAmB;AACrD,QAAI,gBAAgB;AAClB,YAAM,SAAS,oBAAoB,EAAE,SAAS,KAAK,eAAe,CAAC,EAAE,CAAC;AACtE,aAAO;AAAA,QACL,UAAU,CAAC,EAAE,KAAK,UAAU,oBAAoB,MAAM,KAAK,UAAU,QAAQ,MAAM,CAAC,EAAE,CAAC;AAAA,MACzF;AAAA,IACF;AAEA,UAAM,IAAI,MAAM,0BAA0B,IAAI,EAAE;AAAA,EAClD,CAAC;AAGD,QAAM,YAAY,IAAI,qBAAqB;AAC3C,QAAM,OAAO,QAAQ,SAAS;AAG9B,QAAM,qBAAqB,YAAY,MAAM;AAC3C,QAAI;AAAE,mBAAa;AAAA,IAAG,QAAQ;AAAA,IAAC;AAAA,EACjC,GAAG,GAAM;AAGT,UAAQ,GAAG,UAAU,MAAM;AACzB,kBAAc,kBAAkB;AAChC,YAAQ;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACD,UAAQ,GAAG,WAAW,MAAM;AAC1B,kBAAc,kBAAkB;AAChC,YAAQ;AACR,YAAQ,KAAK,CAAC;AAAA,EAChB,CAAC;AACH;","names":["rows","result","nanoid","nanoid","getProjectRoot","getNode","listProjects"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@graph-tl/graph",
3
- "version": "0.1.10",
3
+ "version": "0.1.14",
4
4
  "description": "Agent-native persistent task graph. MCP server for agent planning and execution across sessions.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/tools/agent-config.ts"],"sourcesContent":["// [sl:fV9I7Vel3xT5d_Ws2YHul] Subagent delivery — free for all (retention hook)\n\nconst AGENT_PROMPT = `---\nname: graph\ndescription: Use this agent for tasks tracked in Graph. Enforces the claim-work-resolve workflow — always checks graph_next before working, adds new work to the graph before executing, and resolves with evidence.\ntools: Read, Edit, Write, Bash, Glob, Grep, Task(Explore), AskUserQuestion\nmodel: sonnet\n---\n\nYou are a graph-optimized agent. You execute tasks tracked in a Graph project. Follow this workflow strictly. The human directs, you execute through the graph.\n\n# Workflow\n\n## 1. ORIENT\nOn your first call, orient yourself:\n\\`\\`\\`\ngraph_onboard({ project: \"<project-name>\" })\n\\`\\`\\`\nRead the \\`hint\\` field first — it tells you exactly what to do next. Then read the summary, evidence, knowledge, and actionable tasks.\n\n**First-run:** If the tree is empty and discovery is \\`\"pending\"\\`, this is a brand new project. Jump directly to DISCOVER below. Do not call graph_next on an empty project.\n\n## 2. DISCOVER (when discovery is pending)\nIf the project root or a task node has \\`discovery: \"pending\"\\`, you must complete discovery before decomposing it. Discovery is an interview with the user to understand what needs to happen.\n\nUse AskUserQuestion to cover these areas (adapt to what's relevant — skip what's obvious):\n- **Scope** — What exactly needs to happen? What's explicitly out of scope?\n- **Existing patterns** — How does the codebase currently handle similar things? (explore first, then confirm)\n- **Technical approach** — What libraries, APIs, or patterns should we use?\n- **Acceptance criteria** — How will we know it's done? What does success look like?\n\nAfter the interview:\n1. Write findings as knowledge: \\`graph_knowledge_write({ project, key: \"discovery-<topic>\", content: \"...\" })\\`\n2. Flip discovery to done: \\`graph_update({ updates: [{ node_id: \"<id>\", discovery: \"done\" }] })\\`\n3. NOW decompose with graph_plan\n\nDo NOT skip discovery. If you try to add children to a node with \\`discovery: \"pending\"\\`, graph_plan will reject it.\n\n## 3. CLAIM\nGet your next task:\n\\`\\`\\`\ngraph_next({ project: \"<project-name>\", claim: true })\n\\`\\`\\`\nRead the task summary, ancestor chain (for scope), resolved dependencies (for context on what was done before you), and context links (for files to look at).\n\n## 4. PLAN\nIf you discover work that isn't in the graph, add it BEFORE executing:\n\\`\\`\\`\ngraph_plan({ nodes: [{ ref: \"new-work\", parent_ref: \"<parent-id>\", summary: \"...\" }] })\n\\`\\`\\`\nNever execute ad-hoc work. The graph is the source of truth.\n\nWhen decomposing work:\n- Set dependencies on LEAF nodes, not parent nodes. If \"Page A\" depends on \"Layout\", the dependency is from \"Page A\" to \"Layout\", not from the \"Pages\" parent to \"Layout\".\n- Keep tasks small and specific. A task should be completable in one session.\n- Parent nodes are organizational — they resolve when all children resolve. Don't put work in parent nodes.\n\n## 5. WORK\nExecute the claimed task. While working:\n- Annotate key code changes with \\`// [sl:nodeId]\\` where nodeId is the task you're working on\n- This creates a traceable link from code back to the task, its evidence, and its history\n- Build and run tests before considering a task done\n\n## 6. RESOLVE\nWhen done, resolve the task with evidence:\n\\`\\`\\`\ngraph_update({ updates: [{\n node_id: \"<task-id>\",\n resolved: true,\n add_evidence: [\n { type: \"note\", ref: \"What you did and why\" },\n { type: \"git\", ref: \"<commit-hash> — <summary>\" },\n { type: \"test\", ref: \"Test results\" }\n ],\n add_context_links: [\"path/to/files/you/touched\"]\n}] })\n\\`\\`\\`\nEvidence is mandatory. At minimum, include one note explaining what you did.\n\n## 7. PAUSE\nAfter resolving a task, STOP. Tell the user:\n- What you just completed\n- What the next actionable task is\n- Wait for the user to say \"continue\" before claiming the next task\n\nThe user controls the pace. Do not auto-claim the next task.\n\n# Rules\n\n- NEVER start work without a claimed task\n- NEVER resolve without evidence\n- NEVER execute ad-hoc work — add it to the graph first via graph_plan\n- NEVER auto-continue to the next task — pause and let the user decide\n- ALWAYS build and test before resolving\n- ALWAYS include context_links for files you modified when resolving\n- Parent nodes auto-resolve when all their children are resolved — you don't need to manually resolve them\n- NEVER skip discovery on nodes with discovery:pending — the system will block you from decomposing\n- If you're approaching context limits, ensure your current task's state is captured (update with evidence even if not fully resolved) so the next agent can pick up where you left off\n\n# Common mistakes to avoid\n\n- Setting dependencies on parent nodes instead of leaf nodes\n- Running project scaffolding tools (create-next-app, etc.) before planning in the graph\n- Resolving tasks without running tests\n- Doing work that isn't tracked in the graph\n- Continuing to the next task without pausing for user review\n- Trying to decompose a node without completing discovery first\n- Not writing knowledge entries during discovery — future agents need this context\n`;\n\nexport interface AgentConfigResult {\n agent_file: string;\n install_path: string;\n instructions: string;\n}\n\nexport function handleAgentConfig(): AgentConfigResult {\n return {\n agent_file: AGENT_PROMPT,\n install_path: \".claude/agents/graph.md\",\n instructions:\n \"Save the agent_file content to .claude/agents/graph.md in your project root. \" +\n \"Claude Code will automatically discover it and use it when tasks match the agent description.\",\n };\n}\n"],"mappings":";;;AAEA,IAAM,eAAe;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAkHd,SAAS,oBAAuC;AACrD,SAAO;AAAA,IACL,YAAY;AAAA,IACZ,cAAc;AAAA,IACd,cACE;AAAA,EAEJ;AACF;","names":[]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/nodes.ts","../src/db.ts","../src/events.ts","../src/validate.ts"],"sourcesContent":["import { nanoid } from \"nanoid\";\nimport { getDb } from \"./db.js\";\nimport { logEvent } from \"./events.js\";\nimport { EngineError } from \"./validate.js\";\nimport type { Node, NodeRow, Evidence, FieldChange } from \"./types.js\";\n\n// --- Row <-> Node conversion ---\n\nfunction rowToNode(row: NodeRow): Node {\n return {\n id: row.id,\n rev: row.rev,\n parent: row.parent,\n project: row.project,\n summary: row.summary,\n resolved: row.resolved === 1,\n depth: row.depth,\n discovery: row.discovery ?? null,\n state: row.state ? JSON.parse(row.state) : null,\n properties: JSON.parse(row.properties),\n context_links: JSON.parse(row.context_links),\n evidence: JSON.parse(row.evidence),\n created_by: row.created_by,\n created_at: row.created_at,\n updated_at: row.updated_at,\n };\n}\n\n// --- Create ---\n\nexport interface CreateNodeInput {\n parent?: string;\n project: string;\n summary: string;\n discovery?: string | null;\n state?: unknown;\n properties?: Record<string, unknown>;\n context_links?: string[];\n agent: string;\n}\n\nexport function createNode(input: CreateNodeInput): Node {\n const db = getDb();\n const now = new Date().toISOString();\n const id = nanoid();\n\n // [sl:yBBVr4wcgVfWA_w8U8hQo] Compute depth from parent\n let depth = 0;\n if (input.parent) {\n const parentRow = db.prepare(\"SELECT depth FROM nodes WHERE id = ?\").get(input.parent) as { depth: number } | undefined;\n if (parentRow) depth = parentRow.depth + 1;\n }\n\n const node: Node = {\n id,\n rev: 1,\n parent: input.parent ?? null,\n project: input.project,\n summary: input.summary,\n resolved: false,\n depth,\n discovery: input.discovery ?? null,\n state: input.state ?? null,\n properties: input.properties ?? {},\n context_links: input.context_links ?? [],\n evidence: [],\n created_by: input.agent,\n created_at: now,\n updated_at: now,\n };\n\n db.prepare(`\n INSERT INTO nodes (id, rev, parent, project, summary, resolved, depth, discovery, state, properties, context_links, evidence, created_by, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).run(\n node.id,\n node.rev,\n node.parent,\n node.project,\n node.summary,\n 0,\n node.depth,\n node.discovery,\n node.state !== null ? JSON.stringify(node.state) : null,\n JSON.stringify(node.properties),\n JSON.stringify(node.context_links),\n JSON.stringify(node.evidence),\n node.created_by,\n node.created_at,\n node.updated_at\n );\n\n logEvent(node.id, input.agent, \"created\", [\n { field: \"summary\", before: null, after: node.summary },\n ]);\n\n return node;\n}\n\n// --- Read ---\n\nexport function getNode(id: string): Node | null {\n const db = getDb();\n const row = db.prepare(\"SELECT * FROM nodes WHERE id = ?\").get(id) as\n | NodeRow\n | undefined;\n return row ? rowToNode(row) : null;\n}\n\nexport function getNodeOrThrow(id: string): Node {\n const node = getNode(id);\n if (!node) {\n throw new EngineError(\"node_not_found\", `Node not found: ${id}. Verify the ID is correct and the node hasn't been deleted.`);\n }\n return node;\n}\n\nexport function getChildren(parentId: string): Node[] {\n const db = getDb();\n const rows = db\n .prepare(\"SELECT * FROM nodes WHERE parent = ?\")\n .all(parentId) as NodeRow[];\n return rows.map(rowToNode);\n}\n\nexport function getAncestors(nodeId: string): Array<{ id: string; summary: string; resolved: boolean }> {\n const ancestors: Array<{ id: string; summary: string; resolved: boolean }> = [];\n let current = getNode(nodeId);\n\n while (current?.parent) {\n const parent = getNode(current.parent);\n if (!parent) break;\n ancestors.unshift({ id: parent.id, summary: parent.summary, resolved: parent.resolved });\n current = parent;\n }\n\n return ancestors;\n}\n\nexport function getProjectRoot(project: string): Node | null {\n const db = getDb();\n const row = db\n .prepare(\"SELECT * FROM nodes WHERE project = ? AND parent IS NULL\")\n .get(project) as NodeRow | undefined;\n return row ? rowToNode(row) : null;\n}\n\nexport function listProjects(): Array<{\n project: string;\n id: string;\n summary: string;\n total: number;\n resolved: number;\n unresolved: number;\n updated_at: string;\n}> {\n const db = getDb();\n\n const roots = db\n .prepare(\"SELECT * FROM nodes WHERE parent IS NULL\")\n .all() as NodeRow[];\n\n return roots.map((root) => {\n const counts = db\n .prepare(\n `SELECT\n COUNT(*) as total,\n SUM(CASE WHEN resolved = 1 THEN 1 ELSE 0 END) as resolved\n FROM nodes WHERE project = ?`\n )\n .get(root.project) as { total: number; resolved: number };\n\n return {\n project: root.project,\n id: root.id,\n summary: root.summary,\n total: counts.total,\n resolved: counts.resolved,\n unresolved: counts.total - counts.resolved,\n updated_at: root.updated_at,\n };\n });\n}\n\n// --- Update ---\n\nexport interface UpdateNodeInput {\n node_id: string;\n agent: string;\n resolved?: boolean;\n discovery?: string | null;\n state?: unknown;\n summary?: string;\n properties?: Record<string, unknown>;\n add_context_links?: string[];\n remove_context_links?: string[];\n add_evidence?: Array<{ type: string; ref: string }>;\n}\n\nexport function updateNode(input: UpdateNodeInput): Node {\n const db = getDb();\n const node = getNodeOrThrow(input.node_id);\n const changes: FieldChange[] = [];\n const now = new Date().toISOString();\n\n let newResolved = node.resolved;\n let newDiscovery = node.discovery;\n let newState = node.state;\n let newSummary = node.summary;\n let newProperties = { ...node.properties };\n let newContextLinks = [...node.context_links];\n let newEvidence = [...node.evidence];\n\n // [sl:OZ0or-q5TserCEfWUeMVv] Require evidence when resolving\n if (input.resolved === true && !node.resolved) {\n const hasExistingEvidence = node.evidence.length > 0;\n const hasNewEvidence = input.add_evidence && input.add_evidence.length > 0;\n if (!hasExistingEvidence && !hasNewEvidence) {\n throw new EngineError(\n \"evidence_required\",\n `Cannot resolve node ${input.node_id} without evidence. Add at least one add_evidence entry (type: 'git', 'note', 'test', etc.) explaining what was done.`\n );\n }\n }\n\n if (input.resolved !== undefined && input.resolved !== node.resolved) {\n changes.push({ field: \"resolved\", before: node.resolved, after: input.resolved });\n newResolved = input.resolved;\n }\n\n if (input.discovery !== undefined && input.discovery !== node.discovery) {\n changes.push({ field: \"discovery\", before: node.discovery, after: input.discovery });\n newDiscovery = input.discovery;\n }\n\n if (input.state !== undefined) {\n changes.push({ field: \"state\", before: node.state, after: input.state });\n newState = input.state;\n }\n\n if (input.summary !== undefined && input.summary !== node.summary) {\n changes.push({ field: \"summary\", before: node.summary, after: input.summary });\n newSummary = input.summary;\n }\n\n if (input.properties) {\n for (const [key, value] of Object.entries(input.properties)) {\n if (value === null) {\n if (key in newProperties) {\n changes.push({ field: `properties.${key}`, before: newProperties[key], after: null });\n delete newProperties[key];\n }\n } else {\n changes.push({ field: `properties.${key}`, before: newProperties[key] ?? null, after: value });\n newProperties[key] = value;\n }\n }\n }\n\n if (input.add_context_links) {\n for (const link of input.add_context_links) {\n if (!newContextLinks.includes(link)) {\n newContextLinks.push(link);\n changes.push({ field: \"context_links\", before: null, after: link });\n }\n }\n }\n\n if (input.remove_context_links) {\n for (const link of input.remove_context_links) {\n const idx = newContextLinks.indexOf(link);\n if (idx !== -1) {\n newContextLinks.splice(idx, 1);\n changes.push({ field: \"context_links\", before: link, after: null });\n }\n }\n }\n\n if (input.add_evidence) {\n for (const ev of input.add_evidence) {\n const evidence: Evidence = {\n type: ev.type,\n ref: ev.ref,\n agent: input.agent,\n timestamp: now,\n };\n newEvidence.push(evidence);\n changes.push({ field: \"evidence\", before: null, after: evidence });\n }\n }\n\n if (changes.length === 0) {\n return node;\n }\n\n const newRev = node.rev + 1;\n\n db.prepare(`\n UPDATE nodes SET\n rev = ?,\n resolved = ?,\n discovery = ?,\n state = ?,\n summary = ?,\n properties = ?,\n context_links = ?,\n evidence = ?,\n updated_at = ?\n WHERE id = ?\n `).run(\n newRev,\n newResolved ? 1 : 0,\n newDiscovery,\n newState !== null ? JSON.stringify(newState) : null,\n newSummary,\n JSON.stringify(newProperties),\n JSON.stringify(newContextLinks),\n JSON.stringify(newEvidence),\n now,\n input.node_id\n );\n\n const action = input.resolved === true ? \"resolved\" : \"updated\";\n logEvent(input.node_id, input.agent, action, changes);\n\n return getNodeOrThrow(input.node_id);\n}\n\n// --- Query helpers ---\n\nexport function getProjectSummary(project: string): {\n total: number;\n resolved: number;\n unresolved: number;\n blocked: number;\n actionable: number;\n} {\n const db = getDb();\n\n const counts = db\n .prepare(\n `SELECT\n COUNT(*) as total,\n SUM(CASE WHEN resolved = 1 THEN 1 ELSE 0 END) as resolved\n FROM nodes WHERE project = ?`\n )\n .get(project) as { total: number; resolved: number };\n\n // Blocked: unresolved nodes that have at least one unresolved dependency\n const blocked = db\n .prepare(\n `SELECT COUNT(DISTINCT n.id) as count\n FROM nodes n\n JOIN edges e ON e.from_node = n.id AND e.type = 'depends_on'\n JOIN nodes dep ON dep.id = e.to_node AND dep.resolved = 0\n WHERE n.project = ? AND n.resolved = 0`\n )\n .get(project) as { count: number };\n\n // Actionable: unresolved leaves (no unresolved children) with all deps resolved\n const actionable = db\n .prepare(\n `SELECT COUNT(*) as count FROM nodes n\n WHERE n.project = ? AND n.resolved = 0\n AND NOT EXISTS (\n SELECT 1 FROM nodes child WHERE child.parent = n.id AND child.resolved = 0\n )\n AND NOT EXISTS (\n SELECT 1 FROM edges e\n JOIN nodes dep ON dep.id = e.to_node AND dep.resolved = 0\n WHERE e.from_node = n.id AND e.type = 'depends_on'\n )`\n )\n .get(project) as { count: number };\n\n return {\n total: counts.total,\n resolved: counts.resolved,\n unresolved: counts.total - counts.resolved,\n blocked: blocked.count,\n actionable: actionable.count,\n };\n}\n","import Database from \"better-sqlite3\";\nimport path from \"path\";\n\nlet db: Database.Database;\nlet dbPath: string;\n\nexport function setDbPath(p: string): void {\n dbPath = p;\n}\n\nexport function getDb(): Database.Database {\n if (!db) {\n const resolvedPath = dbPath ?? path.resolve(\"graph.db\");\n db = new Database(resolvedPath);\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"synchronous = FULL\");\n db.pragma(\"foreign_keys = ON\");\n migrate(db);\n }\n return db;\n}\n\nexport function initDb(p?: string): Database.Database {\n // Close existing db if any (used by tests to reset state)\n if (db) {\n db.close();\n db = undefined!;\n }\n if (p) dbPath = p;\n return getDb();\n}\n\nfunction migrate(db: Database.Database): void {\n db.exec(`\n CREATE TABLE IF NOT EXISTS nodes (\n id TEXT PRIMARY KEY,\n rev INTEGER NOT NULL DEFAULT 1,\n parent TEXT REFERENCES nodes(id),\n project TEXT NOT NULL,\n summary TEXT NOT NULL,\n resolved INTEGER NOT NULL DEFAULT 0,\n depth INTEGER NOT NULL DEFAULT 0,\n state TEXT,\n properties TEXT NOT NULL DEFAULT '{}',\n context_links TEXT NOT NULL DEFAULT '[]',\n evidence TEXT NOT NULL DEFAULT '[]',\n created_by TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL\n );\n\n CREATE TABLE IF NOT EXISTS edges (\n id TEXT PRIMARY KEY,\n from_node TEXT NOT NULL REFERENCES nodes(id),\n to_node TEXT NOT NULL REFERENCES nodes(id),\n type TEXT NOT NULL,\n created_at TEXT NOT NULL,\n UNIQUE(from_node, to_node, type)\n );\n\n CREATE TABLE IF NOT EXISTS events (\n id TEXT PRIMARY KEY,\n node_id TEXT NOT NULL REFERENCES nodes(id),\n agent TEXT NOT NULL,\n action TEXT NOT NULL,\n changes TEXT NOT NULL,\n timestamp TEXT NOT NULL\n );\n\n CREATE INDEX IF NOT EXISTS idx_nodes_project ON nodes(project);\n CREATE INDEX IF NOT EXISTS idx_nodes_parent ON nodes(parent);\n CREATE INDEX IF NOT EXISTS idx_nodes_resolved ON nodes(project, resolved);\n CREATE INDEX IF NOT EXISTS idx_edges_from ON edges(from_node);\n CREATE INDEX IF NOT EXISTS idx_edges_to ON edges(to_node);\n CREATE INDEX IF NOT EXISTS idx_edges_type ON edges(from_node, type);\n CREATE INDEX IF NOT EXISTS idx_events_node ON events(node_id);\n\n CREATE TABLE IF NOT EXISTS knowledge (\n id TEXT PRIMARY KEY,\n project TEXT NOT NULL,\n key TEXT NOT NULL,\n content TEXT NOT NULL,\n created_by TEXT NOT NULL,\n created_at TEXT NOT NULL,\n updated_at TEXT NOT NULL,\n UNIQUE(project, key)\n );\n\n CREATE INDEX IF NOT EXISTS idx_knowledge_project ON knowledge(project);\n `);\n\n // [sl:yBBVr4wcgVfWA_w8U8hQo] Migration: add depth column if it doesn't exist\n const hasDepth = db.prepare(\n \"SELECT COUNT(*) as cnt FROM pragma_table_info('nodes') WHERE name = 'depth'\"\n ).get() as { cnt: number };\n\n if (hasDepth.cnt === 0) {\n db.exec(\"ALTER TABLE nodes ADD COLUMN depth INTEGER NOT NULL DEFAULT 0\");\n // Backfill depths using recursive CTE\n db.exec(`\n WITH RECURSIVE tree(id, depth) AS (\n SELECT id, 0 FROM nodes WHERE parent IS NULL\n UNION ALL\n SELECT n.id, t.depth + 1\n FROM nodes n JOIN tree t ON n.parent = t.id\n )\n UPDATE nodes SET depth = (SELECT depth FROM tree WHERE tree.id = nodes.id)\n `);\n }\n\n // [sl:AOXqUIhpW2-gdMqWATf66] Migration: add discovery column if it doesn't exist\n const hasDiscovery = db.prepare(\n \"SELECT COUNT(*) as cnt FROM pragma_table_info('nodes') WHERE name = 'discovery'\"\n ).get() as { cnt: number };\n\n if (hasDiscovery.cnt === 0) {\n db.exec(\"ALTER TABLE nodes ADD COLUMN discovery TEXT DEFAULT NULL\");\n }\n}\n\nexport function checkpointDb(): void {\n if (db) {\n db.pragma(\"wal_checkpoint(TRUNCATE)\");\n }\n}\n\nexport function closeDb(): void {\n if (db) {\n checkpointDb();\n db.close();\n }\n}\n","import { nanoid } from \"nanoid\";\nimport { getDb } from \"./db.js\";\nimport type { FieldChange, Event } from \"./types.js\";\n\nconst INSERT_EVENT = `\n INSERT INTO events (id, node_id, agent, action, changes, timestamp)\n VALUES (?, ?, ?, ?, ?, ?)\n`;\n\nexport function logEvent(\n nodeId: string,\n agent: string,\n action: string,\n changes: FieldChange[]\n): Event {\n const db = getDb();\n const event: Event = {\n id: nanoid(),\n node_id: nodeId,\n agent,\n action,\n changes,\n timestamp: new Date().toISOString(),\n };\n\n db.prepare(INSERT_EVENT).run(\n event.id,\n event.node_id,\n event.agent,\n event.action,\n JSON.stringify(event.changes),\n event.timestamp\n );\n\n return event;\n}\n\nexport function getEvents(\n nodeId: string,\n limit: number = 20,\n cursor?: string\n): { events: Event[]; next_cursor: string | null } {\n const db = getDb();\n\n let query: string;\n let params: unknown[];\n\n if (cursor) {\n query = `\n SELECT * FROM events\n WHERE node_id = ? AND timestamp < ?\n ORDER BY timestamp DESC\n LIMIT ?\n `;\n params = [nodeId, cursor, limit + 1];\n } else {\n query = `\n SELECT * FROM events\n WHERE node_id = ?\n ORDER BY timestamp DESC\n LIMIT ?\n `;\n params = [nodeId, limit + 1];\n }\n\n const rows = db.prepare(query).all(...params) as Array<{\n id: string;\n node_id: string;\n agent: string;\n action: string;\n changes: string;\n timestamp: string;\n }>;\n\n const hasMore = rows.length > limit;\n const slice = hasMore ? rows.slice(0, limit) : rows;\n\n const events: Event[] = slice.map((row) => ({\n id: row.id,\n node_id: row.node_id,\n agent: row.agent,\n action: row.action,\n changes: JSON.parse(row.changes),\n timestamp: row.timestamp,\n }));\n\n return {\n events,\n next_cursor: hasMore ? slice[slice.length - 1].timestamp : null,\n };\n}\n","export class ValidationError extends Error {\n code = \"validation_error\";\n constructor(message: string) {\n super(message);\n this.name = \"ValidationError\";\n }\n}\n\nexport class EngineError extends Error {\n code: string;\n constructor(code: string, message: string) {\n super(message);\n this.name = \"EngineError\";\n this.code = code;\n }\n}\n\nexport function requireString(value: unknown, field: string): string {\n if (typeof value !== \"string\" || value.trim().length === 0) {\n throw new ValidationError(`${field} is required and must be a non-empty string`);\n }\n return value.trim();\n}\n\nexport function optionalString(value: unknown, field: string): string | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"string\") {\n throw new ValidationError(`${field} must be a string`);\n }\n return value;\n}\n\nexport function requireArray<T>(value: unknown, field: string): T[] {\n if (!Array.isArray(value) || value.length === 0) {\n throw new ValidationError(`${field} is required and must be a non-empty array`);\n }\n return value as T[];\n}\n\nexport function optionalArray<T>(value: unknown, field: string): T[] | undefined {\n if (value === undefined || value === null) return undefined;\n if (!Array.isArray(value)) {\n throw new ValidationError(`${field} must be an array`);\n }\n return value as T[];\n}\n\nexport function optionalNumber(value: unknown, field: string, min?: number, max?: number): number | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"number\" || isNaN(value)) {\n throw new ValidationError(`${field} must be a number`);\n }\n if (min !== undefined && value < min) {\n throw new ValidationError(`${field} must be >= ${min}`);\n }\n if (max !== undefined && value > max) {\n throw new ValidationError(`${field} must be <= ${max}`);\n }\n return value;\n}\n\nexport function optionalBoolean(value: unknown, field: string): boolean | undefined {\n if (value === undefined || value === null) return undefined;\n if (typeof value !== \"boolean\") {\n throw new ValidationError(`${field} must be a boolean`);\n }\n return value;\n}\n\nexport function requireObject(value: unknown, field: string): Record<string, unknown> {\n if (value === null || typeof value !== \"object\" || Array.isArray(value)) {\n throw new ValidationError(`${field} is required and must be an object`);\n }\n return value as Record<string, unknown>;\n}\n"],"mappings":"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","names":["nanoid","db","db","db","nanoid"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/init.ts"],"sourcesContent":["import { readFileSync, writeFileSync, existsSync, mkdirSync } from \"fs\";\nimport { join, dirname } from \"path\";\nimport { handleAgentConfig } from \"./tools/agent-config.js\";\n\n// [sl:hy8oXisWnrZN1BfkonUqd] npx @graph-tl/graph init — zero friction onboarding\n\nconst MCP_CONFIG = {\n command: \"npx\",\n args: [\"-y\", \"@graph-tl/graph\"],\n env: {\n GRAPH_AGENT: \"claude-code\",\n },\n};\n\nexport function init(): void {\n const cwd = process.cwd();\n let wrote = false;\n\n // 1. Write .mcp.json\n const configPath = join(cwd, \".mcp.json\");\n if (existsSync(configPath)) {\n try {\n const config = JSON.parse(readFileSync(configPath, \"utf8\"));\n if (config.mcpServers?.graph) {\n console.log(\"✓ .mcp.json — graph already configured\");\n } else {\n config.mcpServers = config.mcpServers ?? {};\n config.mcpServers.graph = MCP_CONFIG;\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf8\");\n console.log(\"✓ .mcp.json — added graph server\");\n wrote = true;\n }\n } catch {\n console.error(`✗ .mcp.json exists but is not valid JSON — skipping`);\n }\n } else {\n const config = { mcpServers: { graph: MCP_CONFIG } };\n writeFileSync(configPath, JSON.stringify(config, null, 2) + \"\\n\", \"utf8\");\n console.log(\"✓ .mcp.json — created with graph server\");\n wrote = true;\n }\n\n // 2. Write .claude/agents/graph.md\n const agentPath = join(cwd, \".claude\", \"agents\", \"graph.md\");\n if (existsSync(agentPath)) {\n console.log(\"✓ .claude/agents/graph.md — already exists\");\n } else {\n const { agent_file } = handleAgentConfig();\n mkdirSync(dirname(agentPath), { recursive: true });\n writeFileSync(agentPath, agent_file, \"utf8\");\n console.log(\"✓ .claude/agents/graph.md — created graph workflow agent\");\n wrote = true;\n }\n\n // 3. Summary\n console.log(\"\");\n if (wrote) {\n console.log(\"Graph is ready. Restart Claude Code to load the MCP server.\");\n console.log(\"\");\n console.log(\"Then try:\");\n console.log(' \"Use graph to plan building a REST API with auth and tests.\"');\n } else {\n console.log(\"Graph is already set up — nothing to do.\");\n }\n}\n"],"mappings":";;;;;;AAAA,SAAS,cAAc,eAAe,YAAY,iBAAiB;AACnE,SAAS,MAAM,eAAe;AAK9B,IAAM,aAAa;AAAA,EACjB,SAAS;AAAA,EACT,MAAM,CAAC,MAAM,iBAAiB;AAAA,EAC9B,KAAK;AAAA,IACH,aAAa;AAAA,EACf;AACF;AAEO,SAAS,OAAa;AAC3B,QAAM,MAAM,QAAQ,IAAI;AACxB,MAAI,QAAQ;AAGZ,QAAM,aAAa,KAAK,KAAK,WAAW;AACxC,MAAI,WAAW,UAAU,GAAG;AAC1B,QAAI;AACF,YAAM,SAAS,KAAK,MAAM,aAAa,YAAY,MAAM,CAAC;AAC1D,UAAI,OAAO,YAAY,OAAO;AAC5B,gBAAQ,IAAI,kDAAwC;AAAA,MACtD,OAAO;AACL,eAAO,aAAa,OAAO,cAAc,CAAC;AAC1C,eAAO,WAAW,QAAQ;AAC1B,sBAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,MAAM;AACxE,gBAAQ,IAAI,4CAAkC;AAC9C,gBAAQ;AAAA,MACV;AAAA,IACF,QAAQ;AACN,cAAQ,MAAM,+DAAqD;AAAA,IACrE;AAAA,EACF,OAAO;AACL,UAAM,SAAS,EAAE,YAAY,EAAE,OAAO,WAAW,EAAE;AACnD,kBAAc,YAAY,KAAK,UAAU,QAAQ,MAAM,CAAC,IAAI,MAAM,MAAM;AACxE,YAAQ,IAAI,mDAAyC;AACrD,YAAQ;AAAA,EACV;AAGA,QAAM,YAAY,KAAK,KAAK,WAAW,UAAU,UAAU;AAC3D,MAAI,WAAW,SAAS,GAAG;AACzB,YAAQ,IAAI,sDAA4C;AAAA,EAC1D,OAAO;AACL,UAAM,EAAE,WAAW,IAAI,kBAAkB;AACzC,cAAU,QAAQ,SAAS,GAAG,EAAE,WAAW,KAAK,CAAC;AACjD,kBAAc,WAAW,YAAY,MAAM;AAC3C,YAAQ,IAAI,oEAA0D;AACtE,YAAQ;AAAA,EACV;AAGA,UAAQ,IAAI,EAAE;AACd,MAAI,OAAO;AACT,YAAQ,IAAI,6DAA6D;AACzE,YAAQ,IAAI,EAAE;AACd,YAAQ,IAAI,WAAW;AACvB,YAAQ,IAAI,gEAAgE;AAAA,EAC9E,OAAO;AACL,YAAQ,IAAI,+CAA0C;AAAA,EACxD;AACF;","names":[]}