@kodus/kodus-graph 0.2.5 → 0.2.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kodus/kodus-graph",
3
- "version": "0.2.5",
3
+ "version": "0.2.6",
4
4
  "description": "Code graph builder for Kodus code review — parses source code into structural graphs with nodes, edges, and analysis",
5
5
  "type": "module",
6
6
  "bin": {
@@ -74,18 +74,17 @@ export function computeStructuralDiff(
74
74
  } else {
75
75
  const newN = newNodesMap.get(qn)!;
76
76
  const changes: string[] = [];
77
- // Detect real changes vs. pure displacement using content_hash.
78
- // content_hash is per-node (SHA256 of the function/class source text).
79
- // If both have content_hash: definitive comparison — same hash = identical content.
80
- // If either is missing (legacy data): fallback to size heuristic.
81
- if (n.line_start !== newN.line_start || n.line_end !== newN.line_end) {
82
- if (n.content_hash && newN.content_hash) {
83
- if (n.content_hash !== newN.content_hash) changes.push('line_range');
84
- } else {
85
- const oldSize = n.line_end - n.line_start;
86
- const newSize = newN.line_end - newN.line_start;
87
- if (oldSize !== newSize) changes.push('line_range');
88
- }
77
+ // Detect real content changes vs. pure displacement.
78
+ // content_hash = SHA256 of the node's source text (position-independent).
79
+ if (n.content_hash && newN.content_hash) {
80
+ // Definitive: hash comparison catches ALL content changes,
81
+ // even same-line-count edits (e.g. `return 1` `return 2`).
82
+ if (n.content_hash !== newN.content_hash) changes.push('body');
83
+ } else if (n.line_start !== newN.line_start || n.line_end !== newN.line_end) {
84
+ // Fallback (legacy data without content_hash): size heuristic.
85
+ const oldSize = n.line_end - n.line_start;
86
+ const newSize = newN.line_end - newN.line_start;
87
+ if (oldSize !== newSize) changes.push('line_range');
89
88
  }
90
89
  if ((n.params || '') !== (newN.params || '')) changes.push('params');
91
90
  if ((n.return_type || '') !== (newN.return_type || '')) changes.push('return_type');
@@ -118,16 +118,56 @@ export function formatPrompt(output: ContextV2Output): string {
118
118
  lines.push('');
119
119
  }
120
120
 
121
- // Structural diff summary
121
+ // Structural diff
122
122
  const diff = analysis.structural_diff;
123
- if (diff.summary.added > 0 || diff.summary.removed > 0 || diff.summary.modified > 0) {
123
+ const hasNodeChanges = diff.summary.added > 0 || diff.summary.removed > 0 || diff.summary.modified > 0;
124
+ const hasEdgeChanges = diff.edges.added.length > 0 || diff.edges.removed.length > 0;
125
+
126
+ if (hasNodeChanges || hasEdgeChanges) {
124
127
  lines.push('## Structural Changes');
125
128
  lines.push('');
126
- const parts: string[] = [];
127
- if (diff.summary.added > 0) parts.push(`${diff.summary.added} added`);
128
- if (diff.summary.removed > 0) parts.push(`${diff.summary.removed} removed`);
129
- if (diff.summary.modified > 0) parts.push(`${diff.summary.modified} modified`);
130
- lines.push(parts.join(', '));
129
+
130
+ if (hasNodeChanges) {
131
+ const parts: string[] = [];
132
+ if (diff.summary.added > 0) parts.push(`${diff.summary.added} added`);
133
+ if (diff.summary.removed > 0) parts.push(`${diff.summary.removed} removed`);
134
+ if (diff.summary.modified > 0) parts.push(`${diff.summary.modified} modified`);
135
+ lines.push(parts.join(', '));
136
+ }
137
+
138
+ if (diff.nodes.removed.length > 0) {
139
+ lines.push('');
140
+ lines.push('Removed:');
141
+ for (const n of diff.nodes.removed) {
142
+ const name = n.qualified_name.split('::').pop();
143
+ lines.push(` - [${n.kind}] ${name} [${n.file_path}:${n.line_start}]`);
144
+ }
145
+ }
146
+
147
+ if (diff.nodes.modified.length > 0) {
148
+ lines.push('');
149
+ lines.push('Modified:');
150
+ for (const m of diff.nodes.modified) {
151
+ const name = m.qualified_name.split('::').pop();
152
+ lines.push(` - ${name} (${m.changes.join(', ')})`);
153
+ }
154
+ }
155
+
156
+ if (hasEdgeChanges) {
157
+ lines.push('');
158
+ lines.push('Dependency changes:');
159
+ for (const e of diff.edges.added) {
160
+ const src = e.source_qualified.split('::').pop();
161
+ const tgt = e.target_qualified.split('::').pop();
162
+ lines.push(` + ${e.kind}: ${src} → ${tgt}`);
163
+ }
164
+ for (const e of diff.edges.removed) {
165
+ const src = e.source_qualified.split('::').pop();
166
+ const tgt = e.target_qualified.split('::').pop();
167
+ lines.push(` - ${e.kind}: ${src} → ${tgt}`);
168
+ }
169
+ }
170
+
131
171
  lines.push('');
132
172
  }
133
173