@graph-tl/graph 0.1.6 → 0.1.9
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 +74 -94
- package/dist/chunk-ILTJI4ZN.js +122 -0
- package/dist/chunk-ILTJI4ZN.js.map +1 -0
- package/dist/{chunk-NWCUIW6D.js → chunk-TWT5GUXW.js} +19 -3
- package/dist/chunk-TWT5GUXW.js.map +1 -0
- package/dist/index.js +2 -2
- package/dist/init-PPICS5PC.js +61 -0
- package/dist/init-PPICS5PC.js.map +1 -0
- package/dist/{nodes-7UZATPPU.js → nodes-4OJBNDHG.js} +2 -2
- package/dist/{server-6MALRQNH.js → server-L7KF2UWS.js} +269 -116
- package/dist/server-L7KF2UWS.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-NWCUIW6D.js.map +0 -1
- package/dist/init-JYP72OZQ.js +0 -39
- package/dist/init-JYP72OZQ.js.map +0 -1
- package/dist/server-6MALRQNH.js.map +0 -1
- /package/dist/{nodes-7UZATPPU.js.map → nodes-4OJBNDHG.js.map} +0 -0
|
@@ -2,6 +2,9 @@
|
|
|
2
2
|
import {
|
|
3
3
|
getLicenseTier
|
|
4
4
|
} from "./chunk-WKOEKYTF.js";
|
|
5
|
+
import {
|
|
6
|
+
handleAgentConfig
|
|
7
|
+
} from "./chunk-ILTJI4ZN.js";
|
|
5
8
|
import {
|
|
6
9
|
EngineError,
|
|
7
10
|
ValidationError,
|
|
@@ -25,14 +28,17 @@ import {
|
|
|
25
28
|
requireString,
|
|
26
29
|
setDbPath,
|
|
27
30
|
updateNode
|
|
28
|
-
} from "./chunk-
|
|
31
|
+
} from "./chunk-TWT5GUXW.js";
|
|
29
32
|
|
|
30
33
|
// src/server.ts
|
|
31
34
|
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
|
|
32
35
|
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
33
36
|
import {
|
|
34
37
|
CallToolRequestSchema,
|
|
35
|
-
ListToolsRequestSchema
|
|
38
|
+
ListToolsRequestSchema,
|
|
39
|
+
ListResourcesRequestSchema,
|
|
40
|
+
ListResourceTemplatesRequestSchema,
|
|
41
|
+
ReadResourceRequestSchema
|
|
36
42
|
} from "@modelcontextprotocol/sdk/types.js";
|
|
37
43
|
|
|
38
44
|
// src/tools/open.ts
|
|
@@ -43,15 +49,28 @@ function handleOpen(input, agent) {
|
|
|
43
49
|
return { projects: listProjects() };
|
|
44
50
|
}
|
|
45
51
|
let root = getProjectRoot(project);
|
|
52
|
+
let isNew = false;
|
|
46
53
|
if (!root) {
|
|
47
54
|
root = createNode({
|
|
48
55
|
project,
|
|
49
56
|
summary: goal ?? project,
|
|
57
|
+
discovery: "pending",
|
|
50
58
|
agent
|
|
51
59
|
});
|
|
60
|
+
isNew = true;
|
|
52
61
|
}
|
|
53
62
|
const summary = getProjectSummary(project);
|
|
54
|
-
|
|
63
|
+
const result = { project, root, summary };
|
|
64
|
+
if (isNew) {
|
|
65
|
+
result.hint = `New project created. Discovery is pending \u2014 interview the user to understand scope and goals, then set discovery to "done" via graph_update before decomposing with graph_plan.`;
|
|
66
|
+
} else if (root.discovery === "pending") {
|
|
67
|
+
result.hint = `Discovery is still pending on this project. Complete the discovery interview, then set discovery to "done" via graph_update.`;
|
|
68
|
+
} else if (summary.actionable > 0) {
|
|
69
|
+
result.hint = `${summary.actionable} actionable task(s). Use graph_next to claim one.`;
|
|
70
|
+
} else if (summary.unresolved > 0 && summary.actionable === 0) {
|
|
71
|
+
result.hint = `All remaining tasks are blocked. Check dependencies with graph_query.`;
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
55
74
|
}
|
|
56
75
|
|
|
57
76
|
// src/edges.ts
|
|
@@ -220,6 +239,12 @@ function handlePlan(input, agent) {
|
|
|
220
239
|
let project;
|
|
221
240
|
if (parentId) {
|
|
222
241
|
const parentNode = getNode(parentId);
|
|
242
|
+
if (parentNode.discovery === "pending") {
|
|
243
|
+
throw new EngineError(
|
|
244
|
+
"discovery_pending",
|
|
245
|
+
`Cannot add children to "${parentNode.summary}" \u2014 discovery is pending. Complete the discovery interview first (set discovery to 'done' via graph_update), then decompose.`
|
|
246
|
+
);
|
|
247
|
+
}
|
|
223
248
|
project = parentNode.project;
|
|
224
249
|
} else {
|
|
225
250
|
throw new Error(
|
|
@@ -286,16 +311,21 @@ function handleUpdate(input, agent) {
|
|
|
286
311
|
const resolvedIds = [];
|
|
287
312
|
let project = null;
|
|
288
313
|
for (const entry of updates) {
|
|
314
|
+
let evidence = entry.add_evidence;
|
|
315
|
+
if (entry.resolved_reason) {
|
|
316
|
+
evidence = [...evidence ?? [], { type: "note", ref: entry.resolved_reason }];
|
|
317
|
+
}
|
|
289
318
|
const node = updateNode({
|
|
290
319
|
node_id: entry.node_id,
|
|
291
320
|
agent,
|
|
292
321
|
resolved: entry.resolved,
|
|
322
|
+
discovery: entry.discovery,
|
|
293
323
|
state: entry.state,
|
|
294
324
|
summary: entry.summary,
|
|
295
325
|
properties: entry.properties,
|
|
296
326
|
add_context_links: entry.add_context_links,
|
|
297
327
|
remove_context_links: entry.remove_context_links,
|
|
298
|
-
add_evidence:
|
|
328
|
+
add_evidence: evidence
|
|
299
329
|
});
|
|
300
330
|
updated.push({ node_id: node.id, rev: node.rev });
|
|
301
331
|
if (entry.resolved === true) {
|
|
@@ -303,10 +333,42 @@ function handleUpdate(input, agent) {
|
|
|
303
333
|
project = node.project;
|
|
304
334
|
}
|
|
305
335
|
}
|
|
336
|
+
const autoResolved = [];
|
|
337
|
+
if (resolvedIds.length > 0) {
|
|
338
|
+
const seen = new Set(resolvedIds);
|
|
339
|
+
const queue = [...resolvedIds];
|
|
340
|
+
while (queue.length > 0) {
|
|
341
|
+
const nodeId = queue.shift();
|
|
342
|
+
const node = getNode(nodeId);
|
|
343
|
+
if (!node?.parent) continue;
|
|
344
|
+
const parentId = node.parent;
|
|
345
|
+
if (seen.has(parentId)) continue;
|
|
346
|
+
seen.add(parentId);
|
|
347
|
+
const parent = getNode(parentId);
|
|
348
|
+
if (!parent || parent.resolved) continue;
|
|
349
|
+
const children = getChildren(parentId);
|
|
350
|
+
if (children.length === 0) continue;
|
|
351
|
+
if (children.every((c) => c.resolved)) {
|
|
352
|
+
const resolved = updateNode({
|
|
353
|
+
node_id: parentId,
|
|
354
|
+
agent,
|
|
355
|
+
resolved: true,
|
|
356
|
+
add_evidence: [{ type: "note", ref: "Auto-resolved: all children completed" }]
|
|
357
|
+
});
|
|
358
|
+
updated.push({ node_id: resolved.id, rev: resolved.rev });
|
|
359
|
+
resolvedIds.push(parentId);
|
|
360
|
+
autoResolved.push({ node_id: parentId, summary: parent.summary });
|
|
361
|
+
queue.push(parentId);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
306
365
|
const result = { updated };
|
|
307
366
|
if (resolvedIds.length > 0 && project) {
|
|
308
367
|
result.newly_actionable = findNewlyActionable(project, resolvedIds);
|
|
309
368
|
}
|
|
369
|
+
if (autoResolved.length > 0) {
|
|
370
|
+
result.auto_resolved = autoResolved;
|
|
371
|
+
}
|
|
310
372
|
return result;
|
|
311
373
|
}
|
|
312
374
|
|
|
@@ -373,6 +435,7 @@ function buildNodeTree(nodeId, currentDepth, maxDepth) {
|
|
|
373
435
|
id: node.id,
|
|
374
436
|
summary: node.summary,
|
|
375
437
|
resolved: node.resolved,
|
|
438
|
+
discovery: node.discovery,
|
|
376
439
|
state: node.state
|
|
377
440
|
};
|
|
378
441
|
if (children.length === 0) {
|
|
@@ -866,9 +929,26 @@ function handleHistory(input) {
|
|
|
866
929
|
|
|
867
930
|
// src/tools/onboard.ts
|
|
868
931
|
function handleOnboard(input) {
|
|
869
|
-
const project = requireString(input?.project, "project");
|
|
870
932
|
const evidenceLimit = optionalNumber(input?.evidence_limit, "evidence_limit", 1, 50) ?? 20;
|
|
871
933
|
const db = getDb();
|
|
934
|
+
let project = optionalString(input?.project, "project");
|
|
935
|
+
if (!project) {
|
|
936
|
+
const projects = listProjects();
|
|
937
|
+
if (projects.length === 0) {
|
|
938
|
+
return {
|
|
939
|
+
projects: [],
|
|
940
|
+
hint: 'No projects yet. Create one with graph_open({ project: "my-project", goal: "..." }).'
|
|
941
|
+
};
|
|
942
|
+
}
|
|
943
|
+
if (projects.length === 1) {
|
|
944
|
+
project = projects[0].project;
|
|
945
|
+
} else {
|
|
946
|
+
return {
|
|
947
|
+
projects,
|
|
948
|
+
hint: `${projects.length} projects found. Call graph_onboard with a specific project name.`
|
|
949
|
+
};
|
|
950
|
+
}
|
|
951
|
+
}
|
|
872
952
|
const root = getProjectRoot(project);
|
|
873
953
|
if (!root) {
|
|
874
954
|
throw new EngineError("project_not_found", `Project not found: ${project}`);
|
|
@@ -885,6 +965,7 @@ function handleOnboard(input) {
|
|
|
885
965
|
id: child.id,
|
|
886
966
|
summary: child.summary,
|
|
887
967
|
resolved: child.resolved === 1,
|
|
968
|
+
discovery: child.discovery,
|
|
888
969
|
children: grandchildren.map((gc) => ({
|
|
889
970
|
id: gc.id,
|
|
890
971
|
summary: gc.summary,
|
|
@@ -919,6 +1000,7 @@ function handleOnboard(input) {
|
|
|
919
1000
|
}
|
|
920
1001
|
}
|
|
921
1002
|
const context_links = [...linkSet].sort();
|
|
1003
|
+
const knowledgeRows = db.prepare("SELECT key, content, updated_at FROM knowledge WHERE project = ? ORDER BY updated_at DESC").all(project);
|
|
922
1004
|
const actionableRows = db.prepare(
|
|
923
1005
|
`SELECT n.id, n.summary, n.properties FROM nodes n
|
|
924
1006
|
WHERE n.project = ? AND n.resolved = 0
|
|
@@ -941,115 +1023,88 @@ function handleOnboard(input) {
|
|
|
941
1023
|
summary: row.summary,
|
|
942
1024
|
properties: JSON.parse(row.properties)
|
|
943
1025
|
}));
|
|
1026
|
+
const oneDayAgo = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
|
|
1027
|
+
const recentlyResolvedRows = db.prepare(
|
|
1028
|
+
`SELECT id, summary, updated_at,
|
|
1029
|
+
(SELECT json_extract(value, '$.agent') FROM json_each(evidence) ORDER BY json_extract(value, '$.timestamp') DESC LIMIT 1) as last_agent
|
|
1030
|
+
FROM nodes
|
|
1031
|
+
WHERE project = ? AND resolved = 1 AND updated_at > ?
|
|
1032
|
+
ORDER BY updated_at DESC
|
|
1033
|
+
LIMIT 10`
|
|
1034
|
+
).all(project, oneDayAgo);
|
|
1035
|
+
const recently_resolved = recentlyResolvedRows.map((row) => ({
|
|
1036
|
+
id: row.id,
|
|
1037
|
+
summary: row.summary,
|
|
1038
|
+
resolved_at: row.updated_at,
|
|
1039
|
+
agent: row.last_agent ?? "unknown"
|
|
1040
|
+
}));
|
|
1041
|
+
const lastActivityRow = db.prepare("SELECT MAX(updated_at) as last FROM nodes WHERE project = ?").get(project);
|
|
1042
|
+
const last_activity = lastActivityRow.last;
|
|
1043
|
+
let hint;
|
|
1044
|
+
if (root.discovery === "pending") {
|
|
1045
|
+
hint = `Discovery is pending. Interview the user to understand scope and goals, write knowledge entries with findings, then set discovery to "done" via graph_update before decomposing with graph_plan.`;
|
|
1046
|
+
} else if (actionable.length > 0) {
|
|
1047
|
+
const recentNote = recently_resolved.length > 0 ? ` ${recently_resolved.length} task(s) resolved recently.` : "";
|
|
1048
|
+
hint = `${actionable.length} actionable task(s) ready.${recentNote} Use graph_next({ project: "${project}", claim: true }) to claim one.`;
|
|
1049
|
+
} else if (summary.unresolved > 0 && summary.actionable === 0) {
|
|
1050
|
+
hint = `All remaining tasks are blocked. Check dependencies with graph_query.`;
|
|
1051
|
+
} else if (summary.total <= 1 && root.discovery !== "pending") {
|
|
1052
|
+
hint = `Project is empty \u2014 use graph_plan to decompose the goal into tasks.`;
|
|
1053
|
+
}
|
|
944
1054
|
return {
|
|
945
1055
|
project,
|
|
1056
|
+
goal: root.summary,
|
|
1057
|
+
discovery: root.discovery,
|
|
1058
|
+
hint,
|
|
946
1059
|
summary,
|
|
947
1060
|
tree,
|
|
948
1061
|
recent_evidence,
|
|
949
1062
|
context_links,
|
|
1063
|
+
knowledge: knowledgeRows,
|
|
1064
|
+
recently_resolved,
|
|
1065
|
+
last_activity,
|
|
950
1066
|
actionable
|
|
951
1067
|
};
|
|
952
1068
|
}
|
|
953
1069
|
|
|
954
|
-
// src/tools/
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
graph_onboard({ project: "<project-name>" })
|
|
970
|
-
\`\`\`
|
|
971
|
-
Read the summary, recent evidence, context links, and actionable tasks. Understand what was done and what's left.
|
|
972
|
-
|
|
973
|
-
## 2. CLAIM
|
|
974
|
-
Get your next task:
|
|
975
|
-
\`\`\`
|
|
976
|
-
graph_next({ project: "<project-name>", claim: true })
|
|
977
|
-
\`\`\`
|
|
978
|
-
Read 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).
|
|
979
|
-
|
|
980
|
-
## 3. PLAN
|
|
981
|
-
If you discover work that isn't in the graph, add it BEFORE executing:
|
|
982
|
-
\`\`\`
|
|
983
|
-
graph_plan({ nodes: [{ ref: "new-work", parent_ref: "<parent-id>", summary: "..." }] })
|
|
984
|
-
\`\`\`
|
|
985
|
-
Never execute ad-hoc work. The graph is the source of truth.
|
|
986
|
-
|
|
987
|
-
When decomposing work:
|
|
988
|
-
- Set dependencies on LEAF nodes, not parent nodes. If "Page A" depends on "Layout", the dependency is from "Page A" to "Layout", not from the "Pages" parent to "Layout".
|
|
989
|
-
- Keep tasks small and specific. A task should be completable in one session.
|
|
990
|
-
- Parent nodes are organizational \u2014 they resolve when all children resolve. Don't put work in parent nodes.
|
|
991
|
-
|
|
992
|
-
## 4. WORK
|
|
993
|
-
Execute the claimed task. While working:
|
|
994
|
-
- Annotate key code changes with \`// [sl:nodeId]\` where nodeId is the task you're working on
|
|
995
|
-
- This creates a traceable link from code back to the task, its evidence, and its history
|
|
996
|
-
- Build and run tests before considering a task done
|
|
997
|
-
|
|
998
|
-
## 5. RESOLVE
|
|
999
|
-
When done, resolve the task with evidence:
|
|
1000
|
-
\`\`\`
|
|
1001
|
-
graph_update({ updates: [{
|
|
1002
|
-
node_id: "<task-id>",
|
|
1003
|
-
resolved: true,
|
|
1004
|
-
add_evidence: [
|
|
1005
|
-
{ type: "note", ref: "What you did and why" },
|
|
1006
|
-
{ type: "git", ref: "<commit-hash> \u2014 <summary>" },
|
|
1007
|
-
{ type: "test", ref: "Test results" }
|
|
1008
|
-
],
|
|
1009
|
-
add_context_links: ["path/to/files/you/touched"]
|
|
1010
|
-
}] })
|
|
1011
|
-
\`\`\`
|
|
1012
|
-
Evidence is mandatory. At minimum, include one note explaining what you did.
|
|
1013
|
-
|
|
1014
|
-
## 6. PAUSE
|
|
1015
|
-
After resolving a task, STOP. Tell the user:
|
|
1016
|
-
- What you just completed
|
|
1017
|
-
- What the next actionable task is
|
|
1018
|
-
- Wait for the user to say "continue" before claiming the next task
|
|
1019
|
-
|
|
1020
|
-
The user controls the pace. Do not auto-claim the next task.
|
|
1021
|
-
|
|
1022
|
-
# Rules
|
|
1023
|
-
|
|
1024
|
-
- NEVER start work without a claimed task
|
|
1025
|
-
- NEVER resolve without evidence
|
|
1026
|
-
- NEVER execute ad-hoc work \u2014 add it to the graph first via graph_plan
|
|
1027
|
-
- NEVER auto-continue to the next task \u2014 pause and let the user decide
|
|
1028
|
-
- ALWAYS build and test before resolving
|
|
1029
|
-
- ALWAYS include context_links for files you modified when resolving
|
|
1030
|
-
- If a parent task becomes actionable (all children resolved), resolve it with a summary of what its children accomplished
|
|
1031
|
-
- 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
|
|
1032
|
-
|
|
1033
|
-
# Common mistakes to avoid
|
|
1034
|
-
|
|
1035
|
-
- Setting dependencies on parent nodes instead of leaf nodes
|
|
1036
|
-
- Running project scaffolding tools (create-next-app, etc.) before planning in the graph
|
|
1037
|
-
- Resolving tasks without running tests
|
|
1038
|
-
- Doing work that isn't tracked in the graph
|
|
1039
|
-
- Continuing to the next task without pausing for user review
|
|
1040
|
-
`;
|
|
1041
|
-
function handleAgentConfig(dbPath) {
|
|
1042
|
-
const tier = getLicenseTier(dbPath);
|
|
1043
|
-
if (tier !== "pro") {
|
|
1044
|
-
throw new EngineError(
|
|
1045
|
-
"free_tier_limit",
|
|
1046
|
-
"The graph-optimized agent configuration is a pro feature. Activate a license key to unlock it."
|
|
1070
|
+
// src/tools/tree.ts
|
|
1071
|
+
function buildTree(node, currentDepth, maxDepth, stats) {
|
|
1072
|
+
stats.total++;
|
|
1073
|
+
if (node.resolved) stats.resolved++;
|
|
1074
|
+
const children = getChildren(node.id);
|
|
1075
|
+
const treeNode = {
|
|
1076
|
+
id: node.id,
|
|
1077
|
+
summary: node.summary,
|
|
1078
|
+
resolved: node.resolved,
|
|
1079
|
+
properties: node.properties
|
|
1080
|
+
};
|
|
1081
|
+
if (children.length === 0) return treeNode;
|
|
1082
|
+
if (currentDepth < maxDepth) {
|
|
1083
|
+
treeNode.children = children.map(
|
|
1084
|
+
(child) => buildTree(child, currentDepth + 1, maxDepth, stats)
|
|
1047
1085
|
);
|
|
1086
|
+
} else {
|
|
1087
|
+
treeNode.child_count = children.length;
|
|
1088
|
+
}
|
|
1089
|
+
return treeNode;
|
|
1090
|
+
}
|
|
1091
|
+
function handleTree(input) {
|
|
1092
|
+
const project = requireString(input?.project, "project");
|
|
1093
|
+
const depth = optionalNumber(input?.depth, "depth", 1, 20) ?? 10;
|
|
1094
|
+
const root = getProjectRoot(project);
|
|
1095
|
+
if (!root) {
|
|
1096
|
+
throw new EngineError("project_not_found", `Project not found: ${project}`);
|
|
1048
1097
|
}
|
|
1098
|
+
const stats = { total: 0, resolved: 0 };
|
|
1099
|
+
const tree = buildTree(root, 0, depth, stats);
|
|
1049
1100
|
return {
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1101
|
+
project,
|
|
1102
|
+
tree,
|
|
1103
|
+
stats: {
|
|
1104
|
+
total: stats.total,
|
|
1105
|
+
resolved: stats.resolved,
|
|
1106
|
+
unresolved: stats.total - stats.resolved
|
|
1107
|
+
}
|
|
1053
1108
|
};
|
|
1054
1109
|
}
|
|
1055
1110
|
|
|
@@ -1132,10 +1187,10 @@ function handleKnowledgeSearch(input) {
|
|
|
1132
1187
|
|
|
1133
1188
|
// src/gates.ts
|
|
1134
1189
|
var FREE_LIMITS = {
|
|
1135
|
-
maxProjects:
|
|
1136
|
-
maxNodesPerProject:
|
|
1137
|
-
onboardEvidenceLimit:
|
|
1138
|
-
scopeEnabled:
|
|
1190
|
+
maxProjects: Infinity,
|
|
1191
|
+
maxNodesPerProject: Infinity,
|
|
1192
|
+
onboardEvidenceLimit: 50,
|
|
1193
|
+
scopeEnabled: true
|
|
1139
1194
|
};
|
|
1140
1195
|
function checkNodeLimit(tier, project, adding) {
|
|
1141
1196
|
if (tier === "pro") return;
|
|
@@ -1163,9 +1218,11 @@ function capEvidenceLimit(tier, requested) {
|
|
|
1163
1218
|
const max = tier === "pro" ? requested ?? 20 : FREE_LIMITS.onboardEvidenceLimit;
|
|
1164
1219
|
return Math.min(requested ?? max, tier === "pro" ? 50 : FREE_LIMITS.onboardEvidenceLimit);
|
|
1165
1220
|
}
|
|
1166
|
-
function
|
|
1167
|
-
|
|
1168
|
-
|
|
1221
|
+
function checkKnowledgeTier(_tier) {
|
|
1222
|
+
return;
|
|
1223
|
+
}
|
|
1224
|
+
function checkScope(_tier, scope) {
|
|
1225
|
+
return scope;
|
|
1169
1226
|
}
|
|
1170
1227
|
|
|
1171
1228
|
// src/server.ts
|
|
@@ -1310,7 +1367,7 @@ var TOOLS = [
|
|
|
1310
1367
|
},
|
|
1311
1368
|
{
|
|
1312
1369
|
name: "graph_update",
|
|
1313
|
-
description: "Update one or more nodes. Can change resolved, state, summary, properties (merged), context_links, and add evidence. When resolving nodes, returns newly_actionable \u2014 nodes that became unblocked. ENFORCED: Resolving a node requires evidence \u2014
|
|
1370
|
+
description: "Update one or more nodes. Can change resolved, state, summary, properties (merged), context_links, and add evidence. When resolving nodes, returns newly_actionable \u2014 nodes that became unblocked. ENFORCED: Resolving a node requires evidence \u2014 use resolved_reason (shorthand, auto-creates note) or add_evidence array (type: 'git' for commits, 'note' for what was done and why, 'test' for results). Also add context_links to files you modified.",
|
|
1314
1371
|
inputSchema: {
|
|
1315
1372
|
type: "object",
|
|
1316
1373
|
properties: {
|
|
@@ -1321,6 +1378,8 @@ var TOOLS = [
|
|
|
1321
1378
|
properties: {
|
|
1322
1379
|
node_id: { type: "string" },
|
|
1323
1380
|
resolved: { type: "boolean" },
|
|
1381
|
+
resolved_reason: { type: "string", description: "Shorthand: auto-creates a note evidence entry. Use instead of add_evidence for simple cases." },
|
|
1382
|
+
discovery: { type: "string", description: "Discovery phase status: 'pending' or 'done'. Set to 'done' after completing discovery interview." },
|
|
1324
1383
|
state: { description: "Agent-defined state, any type" },
|
|
1325
1384
|
summary: { type: "string" },
|
|
1326
1385
|
properties: {
|
|
@@ -1472,18 +1531,32 @@ var TOOLS = [
|
|
|
1472
1531
|
inputSchema: {
|
|
1473
1532
|
type: "object",
|
|
1474
1533
|
properties: {
|
|
1475
|
-
project: { type: "string", description: "Project name (e.g. 'my-project')" },
|
|
1534
|
+
project: { type: "string", description: "Project name (e.g. 'my-project'). Omit to auto-select (works when there's exactly one project)." },
|
|
1476
1535
|
evidence_limit: {
|
|
1477
1536
|
type: "number",
|
|
1478
1537
|
description: "Max evidence entries to return (default 20, max 50)"
|
|
1479
1538
|
}
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1541
|
+
},
|
|
1542
|
+
{
|
|
1543
|
+
name: "graph_tree",
|
|
1544
|
+
description: "Full tree visualization for a project. Returns the complete task hierarchy with resolve status. Use when you need to see the whole project structure beyond graph_context's single-node neighborhood.",
|
|
1545
|
+
inputSchema: {
|
|
1546
|
+
type: "object",
|
|
1547
|
+
properties: {
|
|
1548
|
+
project: { type: "string", description: "Project name (e.g. 'my-project')" },
|
|
1549
|
+
depth: {
|
|
1550
|
+
type: "number",
|
|
1551
|
+
description: "Max tree depth to return (default 10, max 20)"
|
|
1552
|
+
}
|
|
1480
1553
|
},
|
|
1481
1554
|
required: ["project"]
|
|
1482
1555
|
}
|
|
1483
1556
|
},
|
|
1484
1557
|
{
|
|
1485
1558
|
name: "graph_agent_config",
|
|
1486
|
-
description: "Returns the graph-optimized agent configuration file for Claude Code.
|
|
1559
|
+
description: "Returns the graph-optimized agent configuration file for Claude Code. Save the returned content to .claude/agents/graph.md to enable the graph workflow agent.",
|
|
1487
1560
|
inputSchema: {
|
|
1488
1561
|
type: "object",
|
|
1489
1562
|
properties: {}
|
|
@@ -1544,7 +1617,7 @@ async function startServer() {
|
|
|
1544
1617
|
const tier = getLicenseTier(DB_PATH);
|
|
1545
1618
|
const server = new Server(
|
|
1546
1619
|
{ name: "graph", version: PKG_VERSION },
|
|
1547
|
-
{ capabilities: { tools: {} } }
|
|
1620
|
+
{ capabilities: { tools: {}, resources: {} } }
|
|
1548
1621
|
);
|
|
1549
1622
|
checkForUpdate();
|
|
1550
1623
|
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
@@ -1558,7 +1631,7 @@ async function startServer() {
|
|
|
1558
1631
|
case "graph_open": {
|
|
1559
1632
|
const openArgs = args;
|
|
1560
1633
|
if (openArgs?.project) {
|
|
1561
|
-
const { getProjectRoot: getProjectRoot2 } = await import("./nodes-
|
|
1634
|
+
const { getProjectRoot: getProjectRoot2 } = await import("./nodes-4OJBNDHG.js");
|
|
1562
1635
|
if (!getProjectRoot2(openArgs.project)) {
|
|
1563
1636
|
checkProjectLimit(tier);
|
|
1564
1637
|
}
|
|
@@ -1569,7 +1642,7 @@ async function startServer() {
|
|
|
1569
1642
|
case "graph_plan": {
|
|
1570
1643
|
const planArgs = args;
|
|
1571
1644
|
if (planArgs?.nodes?.length > 0) {
|
|
1572
|
-
const { getNode: getNode2 } = await import("./nodes-
|
|
1645
|
+
const { getNode: getNode2 } = await import("./nodes-4OJBNDHG.js");
|
|
1573
1646
|
const firstParent = planArgs.nodes[0]?.parent_ref;
|
|
1574
1647
|
if (firstParent && typeof firstParent === "string" && !planArgs.nodes.some((n) => n.ref === firstParent)) {
|
|
1575
1648
|
const parentNode = getNode2(firstParent);
|
|
@@ -1613,19 +1686,26 @@ async function startServer() {
|
|
|
1613
1686
|
result = handleOnboard(onboardArgs);
|
|
1614
1687
|
break;
|
|
1615
1688
|
}
|
|
1689
|
+
case "graph_tree":
|
|
1690
|
+
result = handleTree(args);
|
|
1691
|
+
break;
|
|
1616
1692
|
case "graph_agent_config":
|
|
1617
|
-
result = handleAgentConfig(
|
|
1693
|
+
result = handleAgentConfig();
|
|
1618
1694
|
break;
|
|
1619
1695
|
case "graph_knowledge_write":
|
|
1696
|
+
checkKnowledgeTier(tier);
|
|
1620
1697
|
result = handleKnowledgeWrite(args, AGENT_IDENTITY);
|
|
1621
1698
|
break;
|
|
1622
1699
|
case "graph_knowledge_read":
|
|
1700
|
+
checkKnowledgeTier(tier);
|
|
1623
1701
|
result = handleKnowledgeRead(args);
|
|
1624
1702
|
break;
|
|
1625
1703
|
case "graph_knowledge_delete":
|
|
1704
|
+
checkKnowledgeTier(tier);
|
|
1626
1705
|
result = handleKnowledgeDelete(args);
|
|
1627
1706
|
break;
|
|
1628
1707
|
case "graph_knowledge_search":
|
|
1708
|
+
checkKnowledgeTier(tier);
|
|
1629
1709
|
result = handleKnowledgeSearch(args);
|
|
1630
1710
|
break;
|
|
1631
1711
|
default:
|
|
@@ -1659,6 +1739,79 @@ async function startServer() {
|
|
|
1659
1739
|
};
|
|
1660
1740
|
}
|
|
1661
1741
|
});
|
|
1742
|
+
server.setRequestHandler(ListResourceTemplatesRequestSchema, async () => ({
|
|
1743
|
+
resourceTemplates: [
|
|
1744
|
+
{
|
|
1745
|
+
uriTemplate: "graph://{project}/tree",
|
|
1746
|
+
name: "Project Tree",
|
|
1747
|
+
description: "Full task tree for a project with resolve status",
|
|
1748
|
+
mimeType: "application/json"
|
|
1749
|
+
},
|
|
1750
|
+
{
|
|
1751
|
+
uriTemplate: "graph://{project}/knowledge",
|
|
1752
|
+
name: "Project Knowledge",
|
|
1753
|
+
description: "All knowledge entries for a project",
|
|
1754
|
+
mimeType: "application/json"
|
|
1755
|
+
},
|
|
1756
|
+
{
|
|
1757
|
+
uriTemplate: "graph://{project}/knowledge/{key}",
|
|
1758
|
+
name: "Knowledge Entry",
|
|
1759
|
+
description: "A specific knowledge entry",
|
|
1760
|
+
mimeType: "application/json"
|
|
1761
|
+
}
|
|
1762
|
+
]
|
|
1763
|
+
}));
|
|
1764
|
+
server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
|
1765
|
+
try {
|
|
1766
|
+
const { listProjects: listProjects2 } = await import("./nodes-4OJBNDHG.js");
|
|
1767
|
+
const projects = listProjects2();
|
|
1768
|
+
const resources = projects.flatMap((p) => [
|
|
1769
|
+
{
|
|
1770
|
+
uri: `graph://${p.project}/tree`,
|
|
1771
|
+
name: `${p.project} \u2014 Tree`,
|
|
1772
|
+
description: `Task tree: ${p.total} nodes (${p.resolved} resolved)`,
|
|
1773
|
+
mimeType: "application/json"
|
|
1774
|
+
},
|
|
1775
|
+
{
|
|
1776
|
+
uri: `graph://${p.project}/knowledge`,
|
|
1777
|
+
name: `${p.project} \u2014 Knowledge`,
|
|
1778
|
+
description: `Knowledge entries for ${p.project}`,
|
|
1779
|
+
mimeType: "application/json"
|
|
1780
|
+
}
|
|
1781
|
+
]);
|
|
1782
|
+
return { resources };
|
|
1783
|
+
} catch {
|
|
1784
|
+
return { resources: [] };
|
|
1785
|
+
}
|
|
1786
|
+
});
|
|
1787
|
+
server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
|
1788
|
+
const uri = request.params.uri;
|
|
1789
|
+
const match = uri.match(/^graph:\/\/([^/]+)\/(.+)$/);
|
|
1790
|
+
if (!match) {
|
|
1791
|
+
throw new Error(`Invalid resource URI: ${uri}`);
|
|
1792
|
+
}
|
|
1793
|
+
const [, project, path] = match;
|
|
1794
|
+
if (path === "tree") {
|
|
1795
|
+
const result = handleTree({ project });
|
|
1796
|
+
return {
|
|
1797
|
+
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(result, null, 2) }]
|
|
1798
|
+
};
|
|
1799
|
+
}
|
|
1800
|
+
if (path === "knowledge") {
|
|
1801
|
+
const result = handleKnowledgeRead({ project });
|
|
1802
|
+
return {
|
|
1803
|
+
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(result, null, 2) }]
|
|
1804
|
+
};
|
|
1805
|
+
}
|
|
1806
|
+
const knowledgeMatch = path.match(/^knowledge\/(.+)$/);
|
|
1807
|
+
if (knowledgeMatch) {
|
|
1808
|
+
const result = handleKnowledgeRead({ project, key: knowledgeMatch[1] });
|
|
1809
|
+
return {
|
|
1810
|
+
contents: [{ uri, mimeType: "application/json", text: JSON.stringify(result, null, 2) }]
|
|
1811
|
+
};
|
|
1812
|
+
}
|
|
1813
|
+
throw new Error(`Unknown resource path: ${path}`);
|
|
1814
|
+
});
|
|
1662
1815
|
const transport = new StdioServerTransport();
|
|
1663
1816
|
await server.connect(transport);
|
|
1664
1817
|
const checkpointInterval = setInterval(() => {
|
|
@@ -1681,4 +1834,4 @@ async function startServer() {
|
|
|
1681
1834
|
export {
|
|
1682
1835
|
startServer
|
|
1683
1836
|
};
|
|
1684
|
-
//# sourceMappingURL=server-
|
|
1837
|
+
//# sourceMappingURL=server-L7KF2UWS.js.map
|