@graph-tl/graph 0.1.0 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +18 -31
- package/dist/{chunk-RVM33A4A.js → chunk-AUC4ED5A.js} +11 -11
- package/dist/chunk-AUC4ED5A.js.map +1 -0
- package/dist/index.js +1 -1
- package/dist/{nodes-75II37NJ.js → nodes-LXNFRN3X.js} +2 -2
- package/dist/{server-7IB2VIMK.js → server-THEPYQC6.js} +18 -7
- package/dist/server-THEPYQC6.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-RVM33A4A.js.map +0 -1
- package/dist/server-7IB2VIMK.js.map +0 -1
- /package/dist/{nodes-75II37NJ.js.map → nodes-LXNFRN3X.js.map} +0 -0
package/README.md
CHANGED
|
@@ -116,41 +116,24 @@ Comments are a snapshot. Graph turns your codebase into a traceable history of d
|
|
|
116
116
|
|
|
117
117
|
## Install
|
|
118
118
|
|
|
119
|
-
|
|
119
|
+
Run this in your project directory:
|
|
120
120
|
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
"mcpServers": {
|
|
124
|
-
"graph": {
|
|
125
|
-
"command": "npx",
|
|
126
|
-
"args": ["-y", "@graph-tl/graph"],
|
|
127
|
-
"env": {
|
|
128
|
-
"GRAPH_AGENT": "claude-code"
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
121
|
+
```bash
|
|
122
|
+
npx -y @graph-tl/graph init
|
|
133
123
|
```
|
|
134
124
|
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
### From source
|
|
125
|
+
This adds Graph to your `.mcp.json`. Restart Claude Code and you're done.
|
|
138
126
|
|
|
139
|
-
|
|
140
|
-
git clone https://github.com/Graph-tl/graph.git
|
|
141
|
-
cd graph
|
|
142
|
-
npm install
|
|
143
|
-
npm run build
|
|
144
|
-
```
|
|
127
|
+
### Manual setup
|
|
145
128
|
|
|
146
|
-
|
|
129
|
+
If you prefer to configure it yourself, add this to `.mcp.json` in your project root:
|
|
147
130
|
|
|
148
131
|
```json
|
|
149
132
|
{
|
|
150
133
|
"mcpServers": {
|
|
151
134
|
"graph": {
|
|
152
|
-
"command": "
|
|
153
|
-
"args": ["
|
|
135
|
+
"command": "npx",
|
|
136
|
+
"args": ["-y", "@graph-tl/graph"],
|
|
154
137
|
"env": {
|
|
155
138
|
"GRAPH_AGENT": "claude-code"
|
|
156
139
|
}
|
|
@@ -159,10 +142,15 @@ Then point your `.mcp.json` at the local build:
|
|
|
159
142
|
}
|
|
160
143
|
```
|
|
161
144
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
145
|
+
### Configuration
|
|
146
|
+
|
|
147
|
+
Environment variables (all optional):
|
|
148
|
+
|
|
149
|
+
| Variable | Default | Description |
|
|
150
|
+
|---|---|---|
|
|
151
|
+
| `GRAPH_AGENT` | `default-agent` | Agent identity, attached to all writes |
|
|
152
|
+
| `GRAPH_DB` | `~/.graph/db/<hash>/graph.db` | SQLite database path. Defaults to a per-project directory in your home folder — no files in your repo. |
|
|
153
|
+
| `GRAPH_CLAIM_TTL` | `60` | Soft claim expiry in minutes |
|
|
166
154
|
|
|
167
155
|
## Tools
|
|
168
156
|
|
|
@@ -199,11 +187,10 @@ The same workflow through a traditional tracker's MCP integration typically cost
|
|
|
199
187
|
|
|
200
188
|
Graph is fully local. Your data never leaves your machine.
|
|
201
189
|
|
|
202
|
-
- **Single SQLite file** — everything is stored in one `.db` file
|
|
190
|
+
- **Single SQLite file** — everything is stored in one `.db` file. By default it lives in `~/.graph/db/` — outside your repo, nothing to gitignore.
|
|
203
191
|
- **No network calls** — Graph is a stdio MCP server. It reads and writes to disk. There is no telemetry, no cloud sync, no external API calls.
|
|
204
192
|
- **No secrets in the graph** — Graph stores task summaries, evidence notes, and file path references. It does not read file contents, access credentials, or store source code.
|
|
205
193
|
- **You control the data** — the SQLite file is yours. Back it up, delete it, move it between machines. There is no account, no server, no lock-in.
|
|
206
|
-
- **Gitignore it** — add `*.db` to your `.gitignore`. The graph contains project-specific planning data that doesn't belong in version control.
|
|
207
194
|
|
|
208
195
|
## Design
|
|
209
196
|
|
|
@@ -7,20 +7,20 @@ import { nanoid as nanoid2 } from "nanoid";
|
|
|
7
7
|
import Database from "better-sqlite3";
|
|
8
8
|
import path from "path";
|
|
9
9
|
var db;
|
|
10
|
+
var dbPath;
|
|
11
|
+
function setDbPath(p) {
|
|
12
|
+
dbPath = p;
|
|
13
|
+
}
|
|
10
14
|
function getDb() {
|
|
11
15
|
if (!db) {
|
|
12
|
-
|
|
16
|
+
const resolvedPath = dbPath ?? path.resolve("graph.db");
|
|
17
|
+
db = new Database(resolvedPath);
|
|
18
|
+
db.pragma("journal_mode = WAL");
|
|
19
|
+
db.pragma("foreign_keys = ON");
|
|
20
|
+
migrate(db);
|
|
13
21
|
}
|
|
14
22
|
return db;
|
|
15
23
|
}
|
|
16
|
-
function initDb(dbPath) {
|
|
17
|
-
const resolvedPath = dbPath ?? path.resolve("graph.db");
|
|
18
|
-
db = new Database(resolvedPath);
|
|
19
|
-
db.pragma("journal_mode = WAL");
|
|
20
|
-
db.pragma("foreign_keys = ON");
|
|
21
|
-
migrate(db);
|
|
22
|
-
return db;
|
|
23
|
-
}
|
|
24
24
|
function migrate(db2) {
|
|
25
25
|
db2.exec(`
|
|
26
26
|
CREATE TABLE IF NOT EXISTS nodes (
|
|
@@ -472,8 +472,8 @@ function getProjectSummary(project) {
|
|
|
472
472
|
}
|
|
473
473
|
|
|
474
474
|
export {
|
|
475
|
+
setDbPath,
|
|
475
476
|
getDb,
|
|
476
|
-
initDb,
|
|
477
477
|
closeDb,
|
|
478
478
|
ValidationError,
|
|
479
479
|
EngineError,
|
|
@@ -494,4 +494,4 @@ export {
|
|
|
494
494
|
updateNode,
|
|
495
495
|
getProjectSummary
|
|
496
496
|
};
|
|
497
|
-
//# sourceMappingURL=chunk-
|
|
497
|
+
//# sourceMappingURL=chunk-AUC4ED5A.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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 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 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 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, 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.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 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 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.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 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 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(\"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\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\nexport function closeDb(): void {\n if (db) {\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"]}
|
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ if (args[0] === "activate") {
|
|
|
9
9
|
const { init } = await import("./init-JYP72OZQ.js");
|
|
10
10
|
init();
|
|
11
11
|
} else {
|
|
12
|
-
const { startServer } = await import("./server-
|
|
12
|
+
const { startServer } = await import("./server-THEPYQC6.js");
|
|
13
13
|
startServer().catch((error) => {
|
|
14
14
|
console.error("Failed to start graph:", error);
|
|
15
15
|
process.exit(1);
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
getProjectSummary,
|
|
10
10
|
listProjects,
|
|
11
11
|
updateNode
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-AUC4ED5A.js";
|
|
13
13
|
export {
|
|
14
14
|
createNode,
|
|
15
15
|
getAncestors,
|
|
@@ -21,4 +21,4 @@ export {
|
|
|
21
21
|
listProjects,
|
|
22
22
|
updateNode
|
|
23
23
|
};
|
|
24
|
-
//# sourceMappingURL=nodes-
|
|
24
|
+
//# sourceMappingURL=nodes-LXNFRN3X.js.map
|
|
@@ -15,7 +15,6 @@ import {
|
|
|
15
15
|
getNodeOrThrow,
|
|
16
16
|
getProjectRoot,
|
|
17
17
|
getProjectSummary,
|
|
18
|
-
initDb,
|
|
19
18
|
listProjects,
|
|
20
19
|
logEvent,
|
|
21
20
|
optionalBoolean,
|
|
@@ -23,8 +22,9 @@ import {
|
|
|
23
22
|
optionalString,
|
|
24
23
|
requireArray,
|
|
25
24
|
requireString,
|
|
25
|
+
setDbPath,
|
|
26
26
|
updateNode
|
|
27
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-AUC4ED5A.js";
|
|
28
28
|
|
|
29
29
|
// src/server.ts
|
|
30
30
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
@@ -1070,9 +1070,20 @@ function checkScope(tier, scope) {
|
|
|
1070
1070
|
}
|
|
1071
1071
|
|
|
1072
1072
|
// src/server.ts
|
|
1073
|
+
import { createHash } from "crypto";
|
|
1074
|
+
import { mkdirSync } from "fs";
|
|
1075
|
+
import { homedir } from "os";
|
|
1076
|
+
import { join, resolve } from "path";
|
|
1073
1077
|
var AGENT_IDENTITY = process.env.GRAPH_AGENT ?? "default-agent";
|
|
1074
|
-
var DB_PATH = process.env.GRAPH_DB ?? "./graph.db";
|
|
1075
1078
|
var CLAIM_TTL = parseInt(process.env.GRAPH_CLAIM_TTL ?? "60", 10);
|
|
1079
|
+
function defaultDbPath() {
|
|
1080
|
+
const projectDir = resolve(".");
|
|
1081
|
+
const hash = createHash("sha256").update(projectDir).digest("hex").slice(0, 16);
|
|
1082
|
+
const dir = join(homedir(), ".graph", "db", hash);
|
|
1083
|
+
mkdirSync(dir, { recursive: true });
|
|
1084
|
+
return join(dir, "graph.db");
|
|
1085
|
+
}
|
|
1086
|
+
var DB_PATH = process.env.GRAPH_DB ?? defaultDbPath();
|
|
1076
1087
|
var TOOLS = [
|
|
1077
1088
|
{
|
|
1078
1089
|
name: "graph_open",
|
|
@@ -1359,7 +1370,7 @@ var TOOLS = [
|
|
|
1359
1370
|
}
|
|
1360
1371
|
];
|
|
1361
1372
|
async function startServer() {
|
|
1362
|
-
|
|
1373
|
+
setDbPath(DB_PATH);
|
|
1363
1374
|
const tier = getLicenseTier(DB_PATH);
|
|
1364
1375
|
const server = new Server(
|
|
1365
1376
|
{ name: "graph", version: "0.1.0" },
|
|
@@ -1376,7 +1387,7 @@ async function startServer() {
|
|
|
1376
1387
|
case "graph_open": {
|
|
1377
1388
|
const openArgs = args;
|
|
1378
1389
|
if (openArgs?.project) {
|
|
1379
|
-
const { getProjectRoot: getProjectRoot2 } = await import("./nodes-
|
|
1390
|
+
const { getProjectRoot: getProjectRoot2 } = await import("./nodes-LXNFRN3X.js");
|
|
1380
1391
|
if (!getProjectRoot2(openArgs.project)) {
|
|
1381
1392
|
checkProjectLimit(tier);
|
|
1382
1393
|
}
|
|
@@ -1387,7 +1398,7 @@ async function startServer() {
|
|
|
1387
1398
|
case "graph_plan": {
|
|
1388
1399
|
const planArgs = args;
|
|
1389
1400
|
if (planArgs?.nodes?.length > 0) {
|
|
1390
|
-
const { getNode: getNode2 } = await import("./nodes-
|
|
1401
|
+
const { getNode: getNode2 } = await import("./nodes-LXNFRN3X.js");
|
|
1391
1402
|
const firstParent = planArgs.nodes[0]?.parent_ref;
|
|
1392
1403
|
if (firstParent && typeof firstParent === "string" && !planArgs.nodes.some((n) => n.ref === firstParent)) {
|
|
1393
1404
|
const parentNode = getNode2(firstParent);
|
|
@@ -1473,4 +1484,4 @@ async function startServer() {
|
|
|
1473
1484
|
export {
|
|
1474
1485
|
startServer
|
|
1475
1486
|
};
|
|
1476
|
-
//# sourceMappingURL=server-
|
|
1487
|
+
//# sourceMappingURL=server-THEPYQC6.js.map
|
|
@@ -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/agent-config.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} from \"@modelcontextprotocol/sdk/types.js\";\nimport { setDbPath, closeDb } 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 { getLicenseTier, type Tier } from \"./license.js\";\nimport { checkNodeLimit, checkProjectLimit, capEvidenceLimit, checkScope } from \"./gates.js\";\n\nimport { createHash } from \"crypto\";\nimport { mkdirSync } from \"fs\";\nimport { homedir } from \"os\";\nimport { join, resolve } from \"path\";\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// 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 },\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 — the engine rejects resolved=true if the node has no existing evidence and no add_evidence in the call. Include at least one add_evidence entry (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 resolved: { type: \"boolean\" },\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). 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\"],\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')\" },\n evidence_limit: {\n type: \"number\",\n description: \"Max evidence entries to return (default 20, max 50)\",\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. Pro tier only. 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\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: \"0.1.0\" },\n { capabilities: { tools: {} } }\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_agent_config\":\n result = handleAgentConfig(DB_PATH);\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 return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\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 // Connect transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n // Cleanup on exit\n process.on(\"SIGINT\", () => {\n closeDb();\n process.exit(0);\n });\n process.on(\"SIGTERM\", () => {\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}\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 };\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\n if (!root) {\n root = createNode({\n project,\n summary: goal ?? project,\n agent,\n });\n }\n\n const summary = getProjectSummary(project);\n\n return { project, root, summary };\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, ValidationError } 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 Error(`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 Error(\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 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 Error(\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 Error(\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 Error(\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 } from \"../nodes.js\";\nimport { findNewlyActionable } from \"../edges.js\";\nimport { requireArray, requireString } from \"../validate.js\";\n\nexport interface UpdateEntry {\n node_id: string;\n resolved?: boolean;\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}\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 let project: string | null = null;\n\n for (const entry of updates) {\n const node = updateNode({\n node_id: entry.node_id,\n agent,\n resolved: entry.resolved,\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: entry.add_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 project = node.project;\n }\n }\n\n const result: UpdateResult = { updated };\n\n if (resolvedIds.length > 0 && project) {\n result.newly_actionable = findNewlyActionable(project, resolvedIds);\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 } 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 state: unknown;\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 state: node.state,\n };\n\n if (children.length === 0) {\n return tree;\n }\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.evidence LIKE ?\");\n params.push(`%\"type\":\"${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 \"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 `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 NextResult {\n nodes: NextResultNode[];\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, leaf (no unresolved children), all deps resolved\n let query = `\n SELECT n.* FROM nodes n\n WHERE n.project = ? AND n.resolved = 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 return { nodes: results };\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 } 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 type RestructureOp = MoveOp | MergeOp | DropOp;\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 (wouldCreateParentCycle(op.node_id, op.new_parent)) {\n throw new Error(\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 // 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 events\n logEvent(op.target, agent, \"merged\", [\n { field: \"merged_from\", before: null, after: op.source },\n ]);\n logEvent(op.source, agent, \"merged_into\", [\n { field: \"merged_into\", before: null, after: op.target },\n ]);\n\n // Delete source node\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\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 {\n throw new Error(`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 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 } from \"../nodes.js\";\nimport { requireString, 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 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 actionable: Array<{\n id: string;\n summary: string;\n properties: Record<string, unknown>;\n }>;\n}\n\nexport function handleOnboard(input: OnboardInput): OnboardResult {\n const project = requireString(input?.project, \"project\");\n const evidenceLimit = optionalNumber(input?.evidence_limit, \"evidence_limit\", 1, 50) ?? 20;\n const db = getDb();\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 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. 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 return {\n project,\n summary,\n tree,\n recent_evidence,\n context_links,\n actionable,\n };\n}\n","import { getLicenseTier } from \"../license.js\";\nimport { EngineError } from \"../validate.js\";\n\n// [sl:fV9I7Vel3xT5d_Ws2YHul] Subagent delivery — pro tier returns agent config\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)\nmodel: sonnet\n---\n\nYou are a graph-optimized agent. You execute tasks tracked in a Graph project. Follow this workflow strictly.\n\n# Workflow\n\n## 1. ORIENT\nOn your first call, orient yourself:\n\\`\\`\\`\ngraph_onboard({ project: \"<project-name>\" })\n\\`\\`\\`\nRead the summary, recent evidence, context links, and actionable tasks. Understand what was done and what's left.\n\n## 2. 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## 3. 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\n## 4. 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\n## 5. 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## 6. LOOP\nCheck the response for \\`newly_actionable\\` tasks. Then call \\`graph_next\\` again for your next task. Repeat until no actionable tasks remain.\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- ALWAYS include context_links for files you modified when resolving\n- If a parent task becomes actionable (all children resolved), resolve it with a summary of what its children accomplished\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\nexport interface AgentConfigResult {\n agent_file: string;\n install_path: string;\n instructions: string;\n}\n\nexport function handleAgentConfig(dbPath?: string): AgentConfigResult {\n const tier = getLicenseTier(dbPath);\n\n if (tier !== \"pro\") {\n throw new EngineError(\n \"free_tier_limit\",\n \"The graph-optimized agent configuration is a pro feature. Activate a license key to unlock it.\"\n );\n }\n\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","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\nconst FREE_LIMITS = {\n maxProjects: 1,\n maxNodesPerProject: 50,\n onboardEvidenceLimit: 5,\n scopeEnabled: false,\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 scope parameter is allowed on free tier.\n * Returns undefined (stripped) if not allowed.\n */\nexport function checkScope(tier: Tier, scope?: string): string | undefined {\n if (tier === \"pro\") return scope;\n return undefined; // silently ignore scope on free tier\n}\n"],"mappings":"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","names":["rows","result","getProjectRoot","getNode"]}
|
package/package.json
CHANGED
|
@@ -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 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 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 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, 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.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 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 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.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 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 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;\n\nexport function getDb(): Database.Database {\n if (!db) {\n throw new Error(\"Database not initialized. Call initDb() first.\");\n }\n return db;\n}\n\nexport function initDb(dbPath?: string): Database.Database {\n const resolvedPath = dbPath ?? path.resolve(\"graph.db\");\n db = new Database(resolvedPath);\n\n db.pragma(\"journal_mode = WAL\");\n db.pragma(\"foreign_keys = ON\");\n\n migrate(db);\n return db;\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\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\nexport function closeDb(): void {\n if (db) {\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/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/agent-config.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} from \"@modelcontextprotocol/sdk/types.js\";\nimport { initDb, closeDb } 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 { getLicenseTier, type Tier } from \"./license.js\";\nimport { checkNodeLimit, checkProjectLimit, capEvidenceLimit, checkScope } from \"./gates.js\";\n\n// Config from env\nconst AGENT_IDENTITY = process.env.GRAPH_AGENT ?? \"default-agent\";\nconst DB_PATH = process.env.GRAPH_DB ?? \"./graph.db\";\nconst CLAIM_TTL = parseInt(process.env.GRAPH_CLAIM_TTL ?? \"60\", 10);\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 },\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 — the engine rejects resolved=true if the node has no existing evidence and no add_evidence in the call. Include at least one add_evidence entry (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 resolved: { type: \"boolean\" },\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). 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\"],\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')\" },\n evidence_limit: {\n type: \"number\",\n description: \"Max evidence entries to return (default 20, max 50)\",\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. Pro tier only. 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\nexport async function startServer(): Promise<void> {\n // Init database\n initDb(DB_PATH);\n\n // [sl:N0IDVJQIhENQFsov6-Lhg] Resolve license tier once at startup\n const tier: Tier = getLicenseTier(DB_PATH);\n\n const server = new Server(\n { name: \"graph\", version: \"0.1.0\" },\n { capabilities: { tools: {} } }\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_agent_config\":\n result = handleAgentConfig(DB_PATH);\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 return {\n content: [{ type: \"text\" as const, text: JSON.stringify(result, null, 2) }],\n };\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 // Connect transport\n const transport = new StdioServerTransport();\n await server.connect(transport);\n\n // Cleanup on exit\n process.on(\"SIGINT\", () => {\n closeDb();\n process.exit(0);\n });\n process.on(\"SIGTERM\", () => {\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}\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 };\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\n if (!root) {\n root = createNode({\n project,\n summary: goal ?? project,\n agent,\n });\n }\n\n const summary = getProjectSummary(project);\n\n return { project, root, summary };\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, ValidationError } 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 Error(`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 Error(\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 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 Error(\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 Error(\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 Error(\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 } from \"../nodes.js\";\nimport { findNewlyActionable } from \"../edges.js\";\nimport { requireArray, requireString } from \"../validate.js\";\n\nexport interface UpdateEntry {\n node_id: string;\n resolved?: boolean;\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}\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 let project: string | null = null;\n\n for (const entry of updates) {\n const node = updateNode({\n node_id: entry.node_id,\n agent,\n resolved: entry.resolved,\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: entry.add_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 project = node.project;\n }\n }\n\n const result: UpdateResult = { updated };\n\n if (resolvedIds.length > 0 && project) {\n result.newly_actionable = findNewlyActionable(project, resolvedIds);\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 } 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 state: unknown;\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 state: node.state,\n };\n\n if (children.length === 0) {\n return tree;\n }\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.evidence LIKE ?\");\n params.push(`%\"type\":\"${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 \"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 `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 NextResult {\n nodes: NextResultNode[];\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, leaf (no unresolved children), all deps resolved\n let query = `\n SELECT n.* FROM nodes n\n WHERE n.project = ? AND n.resolved = 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 return { nodes: results };\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 } 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 type RestructureOp = MoveOp | MergeOp | DropOp;\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 (wouldCreateParentCycle(op.node_id, op.new_parent)) {\n throw new Error(\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 // 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 events\n logEvent(op.target, agent, \"merged\", [\n { field: \"merged_from\", before: null, after: op.source },\n ]);\n logEvent(op.source, agent, \"merged_into\", [\n { field: \"merged_into\", before: null, after: op.target },\n ]);\n\n // Delete source node\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\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 {\n throw new Error(`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 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 } from \"../nodes.js\";\nimport { requireString, 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 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 actionable: Array<{\n id: string;\n summary: string;\n properties: Record<string, unknown>;\n }>;\n}\n\nexport function handleOnboard(input: OnboardInput): OnboardResult {\n const project = requireString(input?.project, \"project\");\n const evidenceLimit = optionalNumber(input?.evidence_limit, \"evidence_limit\", 1, 50) ?? 20;\n const db = getDb();\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 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. 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 return {\n project,\n summary,\n tree,\n recent_evidence,\n context_links,\n actionable,\n };\n}\n","import { getLicenseTier } from \"../license.js\";\nimport { EngineError } from \"../validate.js\";\n\n// [sl:fV9I7Vel3xT5d_Ws2YHul] Subagent delivery — pro tier returns agent config\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)\nmodel: sonnet\n---\n\nYou are a graph-optimized agent. You execute tasks tracked in a Graph project. Follow this workflow strictly.\n\n# Workflow\n\n## 1. ORIENT\nOn your first call, orient yourself:\n\\`\\`\\`\ngraph_onboard({ project: \"<project-name>\" })\n\\`\\`\\`\nRead the summary, recent evidence, context links, and actionable tasks. Understand what was done and what's left.\n\n## 2. 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## 3. 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\n## 4. 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\n## 5. 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## 6. LOOP\nCheck the response for \\`newly_actionable\\` tasks. Then call \\`graph_next\\` again for your next task. Repeat until no actionable tasks remain.\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- ALWAYS include context_links for files you modified when resolving\n- If a parent task becomes actionable (all children resolved), resolve it with a summary of what its children accomplished\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\nexport interface AgentConfigResult {\n agent_file: string;\n install_path: string;\n instructions: string;\n}\n\nexport function handleAgentConfig(dbPath?: string): AgentConfigResult {\n const tier = getLicenseTier(dbPath);\n\n if (tier !== \"pro\") {\n throw new EngineError(\n \"free_tier_limit\",\n \"The graph-optimized agent configuration is a pro feature. Activate a license key to unlock it.\"\n );\n }\n\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","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\nconst FREE_LIMITS = {\n maxProjects: 1,\n maxNodesPerProject: 50,\n onboardEvidenceLimit: 5,\n scopeEnabled: false,\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 scope parameter is allowed on free tier.\n * Returns undefined (stripped) if not allowed.\n */\nexport function checkScope(tier: Tier, scope?: string): string | undefined {\n if (tier === \"pro\") return scope;\n return undefined; // silently ignore scope on free tier\n}\n"],"mappings":"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","names":["rows","result","getProjectRoot","getNode"]}
|
|
File without changes
|