@atoms-tech/atoms-mcp 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,166 @@
1
+ /**
2
+ * atoms_trace — Graph traversal for traceability queries.
3
+ *
4
+ * Answers questions like "which requirements does TC-00003 verify?"
5
+ * or "what's affected if I change REQ-00001?"
6
+ */
7
+ import { getClient } from "../db/client.js";
8
+ import { getItemById } from "../db/queries.js";
9
+ import { formatToolResult, formatErrorResult, success, notFoundError, dbError, authError, } from "./_base.js";
10
+ /** Maximum items returned to prevent huge responses. */
11
+ const MAX_ITEMS = 200;
12
+ /** Relationship types that point "upstream" (toward parents / dependencies). */
13
+ const UPSTREAM_TYPES = ["parent", "verifies"];
14
+ /** Relationship types that point "downstream" (toward dependents). */
15
+ const DOWNSTREAM_TYPES = ["child", "verified_by"];
16
+ /**
17
+ * Inverse mapping: when traversing an incoming edge we need
18
+ * to know what the outgoing type means for the other side.
19
+ */
20
+ const INVERSE_TYPE = {
21
+ parent: "child",
22
+ child: "parent",
23
+ verifies: "verified_by",
24
+ verified_by: "verifies",
25
+ related: "related",
26
+ };
27
+ export async function traceHandler(params) {
28
+ try {
29
+ const maxDepth = Math.min(Math.max(params.depth ?? 5, 1), 10);
30
+ const client = await getClient();
31
+ // Verify root item exists
32
+ const rootItem = await getItemById(client, params.project_id, params.item_id);
33
+ if (!rootItem) {
34
+ return formatErrorResult(notFoundError("Item", params.item_id));
35
+ }
36
+ // Fetch all relationships in the project once (same pattern as export-mermaid)
37
+ const { data: rels, error: relsErr } = await client
38
+ .from("item_relationships")
39
+ .select("from_id, to_id, type")
40
+ .eq("project_id", params.project_id);
41
+ if (relsErr)
42
+ throw new Error(relsErr.message);
43
+ // Fetch all non-deleted items for title/type lookup
44
+ const { data: items, error: itemsErr } = await client
45
+ .from("items")
46
+ .select("id, title, type")
47
+ .eq("project_id", params.project_id)
48
+ .is("deleted_at", null);
49
+ if (itemsErr)
50
+ throw new Error(itemsErr.message);
51
+ const itemMap = new Map();
52
+ for (const item of items ?? []) {
53
+ itemMap.set(item.id, { title: item.title, type: item.type });
54
+ }
55
+ // Build adjacency lists based on direction
56
+ // For each item, we store { neighbor, relType, direction }
57
+ const adjacency = new Map();
58
+ const addEdge = (from, to, relType) => {
59
+ if (!adjacency.has(from))
60
+ adjacency.set(from, []);
61
+ adjacency.get(from).push({ neighbor: to, relType });
62
+ };
63
+ const allowedTypes = params.relationship_types
64
+ ? new Set(params.relationship_types)
65
+ : null;
66
+ for (const rel of rels ?? []) {
67
+ const relType = rel.type;
68
+ // Upstream: follow edges where the item is the source and the rel points upstream
69
+ // i.e., from_id -> to_id with type "parent" or "verifies"
70
+ if (params.direction === "upstream" || params.direction === "both") {
71
+ if (UPSTREAM_TYPES.includes(relType)) {
72
+ if (!allowedTypes || allowedTypes.has(relType)) {
73
+ addEdge(rel.from_id, rel.to_id, relType);
74
+ }
75
+ }
76
+ // Also follow inverse: if from_id has a "child" pointing to to_id,
77
+ // then to_id is upstream of from_id — but we model it as:
78
+ // from_id's downstream is to_id via "child". For upstream from to_id,
79
+ // we'd follow to_id -> from_id via inverse of "child" = "parent".
80
+ if (DOWNSTREAM_TYPES.includes(relType)) {
81
+ const inverseType = INVERSE_TYPE[relType] ?? relType;
82
+ if (!allowedTypes || allowedTypes.has(inverseType)) {
83
+ addEdge(rel.to_id, rel.from_id, inverseType);
84
+ }
85
+ }
86
+ }
87
+ if (params.direction === "downstream" || params.direction === "both") {
88
+ if (DOWNSTREAM_TYPES.includes(relType)) {
89
+ if (!allowedTypes || allowedTypes.has(relType)) {
90
+ addEdge(rel.from_id, rel.to_id, relType);
91
+ }
92
+ }
93
+ // Inverse: upstream type from the other side means downstream for us
94
+ if (UPSTREAM_TYPES.includes(relType)) {
95
+ const inverseType = INVERSE_TYPE[relType] ?? relType;
96
+ if (!allowedTypes || allowedTypes.has(inverseType)) {
97
+ addEdge(rel.to_id, rel.from_id, inverseType);
98
+ }
99
+ }
100
+ }
101
+ // "related" is bidirectional — add both directions if allowed
102
+ if (relType === "related") {
103
+ if (!allowedTypes || allowedTypes.has("related")) {
104
+ addEdge(rel.from_id, rel.to_id, "related");
105
+ addEdge(rel.to_id, rel.from_id, "related");
106
+ }
107
+ }
108
+ }
109
+ // BFS traversal from root
110
+ const visited = new Set();
111
+ visited.add(params.item_id);
112
+ const result = [];
113
+ const queue = [];
114
+ // Seed queue with direct neighbors of the root
115
+ const rootNeighbors = adjacency.get(params.item_id) ?? [];
116
+ for (const edge of rootNeighbors) {
117
+ queue.push({ id: edge.neighbor, depth: 1, relType: edge.relType });
118
+ }
119
+ while (queue.length > 0 && result.length < MAX_ITEMS) {
120
+ const { id, depth, relType } = queue.shift();
121
+ if (visited.has(id) || depth > maxDepth)
122
+ continue;
123
+ visited.add(id);
124
+ const info = itemMap.get(id);
125
+ if (!info)
126
+ continue; // skip deleted items
127
+ result.push({
128
+ id,
129
+ title: info.title,
130
+ type: info.type,
131
+ relationship: relType,
132
+ depth,
133
+ });
134
+ // Enqueue neighbors at next depth
135
+ if (depth < maxDepth) {
136
+ const neighbors = adjacency.get(id) ?? [];
137
+ for (const edge of neighbors) {
138
+ if (!visited.has(edge.neighbor)) {
139
+ queue.push({
140
+ id: edge.neighbor,
141
+ depth: depth + 1,
142
+ relType: edge.relType,
143
+ });
144
+ }
145
+ }
146
+ }
147
+ }
148
+ return formatToolResult(success({
149
+ root: params.item_id,
150
+ direction: params.direction,
151
+ depth_limit: maxDepth,
152
+ items: result,
153
+ total_count: result.length,
154
+ ...(result.length >= MAX_ITEMS
155
+ ? { truncated: true, truncation_message: `Results capped at ${MAX_ITEMS} items. Use a smaller depth or filter by relationship_types.` }
156
+ : {}),
157
+ }));
158
+ }
159
+ catch (err) {
160
+ if (err instanceof Error && err.message.includes("Not authenticated")) {
161
+ return formatErrorResult(authError());
162
+ }
163
+ return formatErrorResult(dbError(err instanceof Error ? err.message : String(err)));
164
+ }
165
+ }
166
+ //# sourceMappingURL=trace.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"trace.js","sourceRoot":"","sources":["../../src/tools/trace.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atoms-tech/atoms-mcp",
3
- "version": "0.1.0",
3
+ "version": "0.2.0",
4
4
  "description": "MCP server for ATOMS.tech — AI agent integration for requirements management",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",