diffintel 0.1.2 → 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.
@@ -49,11 +49,15 @@ async function run(opts) {
49
49
  };
50
50
  const html = (0, html_report_1.renderReport)(report);
51
51
  fs_1.default.writeFileSync(outFile, html, "utf-8");
52
- console.error(`\nTitle: ${explanation.title}`);
53
- console.error(`Files: ${fileDiffs.length} | +${totalAdditions} -${totalDeletions}`);
54
- console.error(`Risks: ${explanation.risks.length > 0 ? explanation.risks.map((r) => `${r.level}: ${r.description}`).join("; ") : "none"}`);
55
- console.error(`Tokens: ${explanation.tokenUsage.input} in / ${explanation.tokenUsage.output} out`);
56
- console.error(`\nReport written to: ${outFile}`);
52
+ console.error(`\n${explanation.title}`);
53
+ console.error(`${fileDiffs.length} files | +${totalAdditions} -${totalDeletions}`);
54
+ if (explanation.fixes.length > 0) {
55
+ console.error(`Fixes: ${explanation.fixes.map((f) => f.description).join("; ")}`);
56
+ }
57
+ if (explanation.risks.length > 0) {
58
+ console.error(`Risks: ${explanation.risks.map((r) => `[${r.level}] ${r.description}`).join("; ")}`);
59
+ }
60
+ console.error(`\nReport: ${outFile}`);
57
61
  return 0;
58
62
  }
59
63
  catch (err) {
@@ -1 +1 @@
1
- {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/commands/explain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"explain.js","sourceRoot":"","sources":["../../src/commands/explain.ts"],"names":[],"mappings":"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"}
@@ -114,13 +114,27 @@ function getFileContent(ref, filePath) {
114
114
  function getFileHistory(filePath, upToRef, count = 5) {
115
115
  try {
116
116
  const log = (0, child_process_1.execSync)(`git log --format="%h|%s|%cr" -${count} ${upToRef} -- ${filePath}`, { encoding: "utf-8" });
117
- return log.trim().split("\n").filter(Boolean).map((line) => {
117
+ const entries = log.trim().split("\n").filter(Boolean).map((line) => {
118
118
  const [hash, message, age] = line.split("|");
119
119
  return { hash, message, age };
120
120
  });
121
+ // Attach the diff from the most recent commit so the LLM can see what just changed
122
+ if (entries.length > 0) {
123
+ entries[0].diff = getCommitFileDiff(entries[0].hash, filePath);
124
+ }
125
+ return entries;
121
126
  }
122
127
  catch {
123
128
  return [];
124
129
  }
125
130
  }
131
+ function getCommitFileDiff(hash, filePath) {
132
+ try {
133
+ const diff = (0, child_process_1.execSync)(`git diff ${hash}~1..${hash} -- ${filePath}`, { encoding: "utf-8" });
134
+ return diff.trim() || undefined;
135
+ }
136
+ catch {
137
+ return undefined;
138
+ }
139
+ }
126
140
  //# sourceMappingURL=git-diff.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"git-diff.js","sourceRoot":"","sources":["../../src/explain/git-diff.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git-diff.js","sourceRoot":"","sources":["../../src/explain/git-diff.ts"],"names":[],"mappings":"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"}
@@ -8,108 +8,237 @@ function escapeHtml(str) {
8
8
  .replace(/>/g, ">")
9
9
  .replace(/"/g, """);
10
10
  }
11
- const STATUS_ICON = {
12
- added: "+", // +
13
- modified: "✎", // pencil
14
- deleted: "✕", // x
15
- renamed: "→", // arrow
16
- };
17
- const ACTION_BADGE = {
18
- added: { label: "added", color: "#22c55e" },
19
- removed: { label: "removed", color: "#ef4444" },
20
- modified: { label: "modified", color: "#f59e0b" },
21
- };
22
- const RISK_COLORS = {
23
- low: { bg: "#dcfce7", text: "#166534" },
24
- medium: { bg: "#fef3c7", text: "#92400e" },
25
- high: { bg: "#fee2e2", text: "#991b1b" },
26
- };
27
11
  function renderReport(report) {
28
12
  const { explanation, summary, files } = report;
29
- const riskBadges = explanation.risks.length > 0
13
+ // --- Fixes section ---
14
+ const fixesHtml = explanation.fixes.length > 0
15
+ ? explanation.fixes.map((f) => `<div class="fix-item"><span class="fix-icon">&#10003;</span> ${escapeHtml(f.description)}</div>`).join("\n")
16
+ : "";
17
+ // --- Risks section ---
18
+ const risksHtml = explanation.risks.length > 0
30
19
  ? explanation.risks.map((r) => {
31
- const c = RISK_COLORS[r.level] || RISK_COLORS.low;
32
- return `<span style="display:inline-block;padding:2px 8px;border-radius:4px;font-size:13px;background:${c.bg};color:${c.text};margin-right:6px;">${r.level.toUpperCase()}: ${escapeHtml(r.description)}</span>`;
20
+ const cls = `risk-${r.level}`;
21
+ return `<div class="risk-item ${cls}"><span class="risk-label">${r.level}</span> ${escapeHtml(r.description)}</div>`;
33
22
  }).join("\n")
34
- : '<span style="color:#166534;">No risks identified</span>';
35
- const filesTable = files.map((f) => {
36
- const icon = STATUS_ICON[f.status] || "";
37
- const changeCount = f.structuralChanges.length;
38
- return `<tr>
39
- <td>${icon}</td>
40
- <td style="font-family:monospace;font-size:13px;">${escapeHtml(f.path)}</td>
41
- <td>${f.status}</td>
42
- <td>${f.language || "—"}</td>
43
- <td>${changeCount}</td>
44
- </tr>`;
45
- }).join("\n");
46
- const fileDetails = files.map((f) => {
47
- const changesList = f.structuralChanges.length > 0
48
- ? "<ul style=\"margin:8px 0;padding-left:20px;\">" +
49
- f.structuralChanges.map((c) => {
50
- const badge = ACTION_BADGE[c.action] || ACTION_BADGE.modified;
51
- return `<li><span style="display:inline-block;padding:1px 6px;border-radius:3px;font-size:11px;background:${badge.color};color:white;margin-right:4px;">${badge.label}</span> <code>${escapeHtml(c.name)}</code> <span style="color:#666;">(${c.type})</span></li>`;
52
- }).join("\n") +
53
- "</ul>"
54
- : "<p style=\"color:#888;margin:8px 0;\">No structural changes detected</p>";
55
- const diffBlock = f.rawDiff
56
- ? `<pre style="background:#1e1e1e;color:#d4d4d4;padding:12px;border-radius:6px;overflow-x:auto;font-size:12px;line-height:1.5;margin:8px 0;">${colorDiff(f.rawDiff)}</pre>`
57
- : "<p style=\"color:#888;\">No diff available</p>";
58
- return `<details style="margin-bottom:12px;border:1px solid #e5e7eb;border-radius:8px;padding:0;">
59
- <summary style="padding:10px 14px;cursor:pointer;font-family:monospace;font-size:14px;background:#f9fafb;border-radius:8px;">${STATUS_ICON[f.status] || ""} ${escapeHtml(f.path)} <span style="color:#888;">(${f.structuralChanges.length} changes)</span></summary>
60
- <div style="padding:10px 14px;">
61
- ${changesList}
62
- ${diffBlock}
23
+ : "";
24
+ // --- Per-file detail cards ---
25
+ // Build a map for both summary and notes
26
+ const fileExplanationData = new Map(explanation.fileExplanations.map((fe) => [fe.path, fe]));
27
+ const fileCards = files.map((f) => {
28
+ const feData = fileExplanationData.get(f.path);
29
+ const changesHtml = f.structuralChanges.length > 0
30
+ ? `<div class="changes-list">${f.structuralChanges.map((c) => {
31
+ const cls = `action-${c.action}`;
32
+ return `<span class="change-badge ${cls}">${c.action}</span> <code>${escapeHtml(c.name)}</code> <span class="change-type">${c.type}</span>`;
33
+ }).join('<br>')}</div>`
34
+ : "";
35
+ const notesHtml = feData?.notes && feData.notes.length > 0
36
+ ? `<div class="file-notes"><div class="file-notes-label">Things to note</div><ul>${feData.notes.map((n) => `<li>${escapeHtml(n)}</li>`).join("")}</ul></div>`
37
+ : "";
38
+ const diffHtml = f.rawDiff
39
+ ? `<details class="diff-toggle"><summary>View diff</summary><pre class="diff-block">${colorDiff(f.rawDiff)}</pre></details>`
40
+ : "";
41
+ return `<div class="file-card">
42
+ <div class="file-header">
43
+ <span class="file-status status-${f.status}">${f.status}</span>
44
+ <span class="file-path">${escapeHtml(f.path)}</span>
63
45
  </div>
64
- </details>`;
46
+ ${feData?.summary ? `<p class="file-summary">${escapeHtml(feData.summary)}</p>` : ""}
47
+ ${notesHtml}
48
+ ${changesHtml}
49
+ ${diffHtml}
50
+ </div>`;
65
51
  }).join("\n");
52
+ // --- Assemble the full report ---
66
53
  return `<!DOCTYPE html>
67
54
  <html lang="en">
68
55
  <head>
69
56
  <meta charset="utf-8">
70
57
  <meta name="viewport" content="width=device-width, initial-scale=1">
71
58
  <title>${escapeHtml(explanation.title)}</title>
59
+ <link rel="preconnect" href="https://fonts.googleapis.com">
60
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
61
+ <link href="https://fonts.googleapis.com/css2?family=Playfair+Display:wght@700;800&family=Inter:wght@400;500;600&display=swap" rel="stylesheet">
72
62
  <style>
73
63
  * { box-sizing: border-box; margin: 0; padding: 0; }
74
- body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; max-width: 900px; margin: 0 auto; padding: 24px; color: #1f2937; background: #fff; line-height: 1.6; }
75
- h1 { font-size: 22px; margin-bottom: 6px; }
76
- h2 { font-size: 16px; margin: 24px 0 10px; color: #374151; border-bottom: 1px solid #e5e7eb; padding-bottom: 6px; }
77
- table { width: 100%; border-collapse: collapse; margin: 10px 0; }
78
- th, td { text-align: left; padding: 6px 10px; border-bottom: 1px solid #f3f4f6; font-size: 13px; }
79
- th { background: #f9fafb; font-weight: 600; }
80
- .stats { display: flex; gap: 16px; margin: 12px 0; }
81
- .stat { padding: 8px 14px; border-radius: 6px; background: #f3f4f6; font-size: 14px; }
82
- .stat b { font-size: 18px; }
83
- .meta { color: #6b7280; font-size: 12px; margin-bottom: 16px; }
64
+ body {
65
+ font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
66
+ max-width: 740px; margin: 0 auto; padding: 48px 20px;
67
+ color: #1a1a1a; background: #fff; line-height: 1.7;
68
+ }
69
+
70
+ /* Article header */
71
+ .article-header {
72
+ margin-bottom: 36px;
73
+ padding-bottom: 28px;
74
+ border-bottom: 1px solid #eee;
75
+ }
76
+ .article-header .label {
77
+ display: inline-block; font-size: 11px; font-weight: 600;
78
+ text-transform: uppercase; letter-spacing: 1.5px; color: #3b82f6;
79
+ margin-bottom: 12px;
80
+ }
81
+ h1 {
82
+ font-family: "Playfair Display", Georgia, "Times New Roman", serif;
83
+ font-size: 34px; font-weight: 800; line-height: 1.2;
84
+ margin-bottom: 16px; letter-spacing: -0.5px; color: #111;
85
+ }
86
+ .meta { color: #999; font-size: 13px; font-weight: 400; }
87
+ .meta span { margin-right: 16px; }
88
+
89
+ /* Stats */
90
+ .stats {
91
+ display: flex; gap: 20px; margin-bottom: 32px;
92
+ }
93
+ .stat {
94
+ font-size: 13px; color: #777; font-weight: 500;
95
+ }
96
+ .stat b { font-size: 18px; color: #1a1a1a; margin-right: 3px; }
97
+ .stat.additions b { color: #16a34a; }
98
+ .stat.deletions b { color: #dc2626; }
99
+
100
+ /* Description — article lede */
101
+ .description {
102
+ font-size: 18px; line-height: 1.85; margin-bottom: 36px;
103
+ color: #333; font-weight: 400;
104
+ }
105
+
106
+ /* Section headings */
107
+ h2 {
108
+ font-size: 12px; font-weight: 600; text-transform: uppercase;
109
+ letter-spacing: 1.2px; color: #999; margin: 36px 0 14px;
110
+ }
111
+
112
+ /* Fixes */
113
+ .fix-item {
114
+ padding: 10px 14px; margin-bottom: 8px;
115
+ background: #f0fdf4; border-left: 3px solid #22c55e;
116
+ border-radius: 0 6px 6px 0; font-size: 14px; color: #15803d;
117
+ }
118
+ .fix-icon { margin-right: 6px; font-weight: bold; }
119
+
120
+ /* Risks */
121
+ .risk-item {
122
+ padding: 10px 14px; margin-bottom: 8px;
123
+ border-radius: 0 6px 6px 0; font-size: 14px;
124
+ }
125
+ .risk-label {
126
+ display: inline-block; padding: 1px 8px; border-radius: 3px;
127
+ font-size: 11px; font-weight: 600; text-transform: uppercase;
128
+ margin-right: 8px; color: white;
129
+ }
130
+ .risk-low { background: #fefce8; border-left: 3px solid #eab308; color: #854d0e; }
131
+ .risk-low .risk-label { background: #eab308; }
132
+ .risk-medium { background: #fff7ed; border-left: 3px solid #f97316; color: #9a3412; }
133
+ .risk-medium .risk-label { background: #f97316; }
134
+ .risk-high { background: #fef2f2; border-left: 3px solid #ef4444; color: #991b1b; }
135
+ .risk-high .risk-label { background: #ef4444; }
136
+
137
+ /* No items */
138
+ .none-msg { color: #aaa; font-size: 14px; font-style: italic; }
139
+
140
+ /* File cards */
141
+ .file-card {
142
+ border: 1px solid #e5e7eb; border-radius: 8px;
143
+ margin-bottom: 16px; overflow: hidden;
144
+ }
145
+ .file-header {
146
+ padding: 10px 14px; background: #fafafa;
147
+ border-bottom: 1px solid #f0f0f0;
148
+ display: flex; align-items: center; gap: 10px;
149
+ }
150
+ .file-path { font-family: "SF Mono", Menlo, monospace; font-size: 13px; }
151
+ .file-status {
152
+ display: inline-block; padding: 2px 8px; border-radius: 4px;
153
+ font-size: 11px; font-weight: 600; text-transform: uppercase; color: white;
154
+ }
155
+ .status-added { background: #22c55e; }
156
+ .status-modified { background: #3b82f6; }
157
+ .status-deleted { background: #ef4444; }
158
+ .status-renamed { background: #8b5cf6; }
159
+
160
+ .file-summary {
161
+ padding: 12px 14px; font-size: 14px; color: #444;
162
+ border-bottom: 1px solid #f5f5f5;
163
+ }
164
+ .file-notes {
165
+ padding: 10px 14px; background: #fafbff;
166
+ border-bottom: 1px solid #f0f0f0;
167
+ }
168
+ .file-notes-label {
169
+ font-size: 11px; font-weight: 600; text-transform: uppercase;
170
+ letter-spacing: 0.8px; color: #7c8db0; margin-bottom: 6px;
171
+ }
172
+ .file-notes ul {
173
+ margin: 0; padding-left: 18px;
174
+ }
175
+ .file-notes li {
176
+ font-size: 13px; color: #555; line-height: 1.6; margin-bottom: 2px;
177
+ }
178
+
179
+ .changes-list {
180
+ padding: 10px 14px; font-size: 13px; line-height: 2;
181
+ }
182
+ .change-badge {
183
+ display: inline-block; padding: 1px 6px; border-radius: 3px;
184
+ font-size: 11px; font-weight: 600; color: white; margin-right: 4px;
185
+ }
186
+ .action-added { background: #22c55e; }
187
+ .action-removed { background: #ef4444; }
188
+ .action-modified { background: #f59e0b; }
189
+ .change-type { color: #999; font-size: 12px; }
190
+ code { font-family: "SF Mono", Menlo, monospace; font-size: 12px; }
191
+
192
+ /* Diff */
193
+ .diff-toggle { margin: 0; }
194
+ .diff-toggle summary {
195
+ padding: 8px 14px; cursor: pointer; font-size: 12px;
196
+ color: #888; user-select: none; border-top: 1px solid #f0f0f0;
197
+ }
198
+ .diff-toggle summary:hover { color: #555; }
199
+ .diff-block {
200
+ background: #1e1e1e; color: #d4d4d4; padding: 14px;
201
+ overflow-x: auto; font-size: 12px; line-height: 1.6;
202
+ font-family: "SF Mono", Menlo, monospace;
203
+ margin: 0; border-radius: 0;
204
+ }
205
+
206
+ /* Footer */
207
+ .footer {
208
+ margin-top: 36px; padding-top: 14px; border-top: 1px solid #eee;
209
+ color: #bbb; font-size: 11px;
210
+ }
84
211
  </style>
85
212
  </head>
86
213
  <body>
87
- <h1>${escapeHtml(explanation.title)}</h1>
88
- <div class="meta">${escapeHtml(report.baseRef)} &rarr; ${escapeHtml(report.headRef)} &middot; ${escapeHtml(report.generatedAt)}</div>
214
+ <div class="article-header">
215
+ <div class="label">Change Report</div>
216
+ <h1>${escapeHtml(explanation.title)}</h1>
217
+ <div class="meta">
218
+ <span>${escapeHtml(report.baseRef)} &rarr; ${escapeHtml(report.headRef)}</span>
219
+ <span>${new Date(report.generatedAt).toLocaleDateString("en-US", { year: "numeric", month: "long", day: "numeric" })}</span>
220
+ </div>
221
+ </div>
89
222
 
90
223
  <div class="stats">
91
- <div class="stat"><b>${summary.filesChanged}</b> files changed</div>
92
- <div class="stat" style="color:#166534;"><b>+${summary.additions}</b> additions</div>
93
- <div class="stat" style="color:#991b1b;"><b>-${summary.deletions}</b> deletions</div>
224
+ <div class="stat"><b>${summary.filesChanged}</b> files</div>
225
+ <div class="stat additions"><b>+${summary.additions}</b> added</div>
226
+ <div class="stat deletions"><b>-${summary.deletions}</b> removed</div>
94
227
  </div>
95
228
 
96
- <h2>Description</h2>
97
- <p style="margin:8px 0;">${escapeHtml(explanation.description)}</p>
229
+ <div class="description">${escapeHtml(explanation.description)}</div>
98
230
 
99
- <h2>Risk Assessment</h2>
100
- <div style="margin:8px 0;">${riskBadges}</div>
231
+ ${fixesHtml ? `<h2>What was fixed</h2>\n${fixesHtml}` : ""}
101
232
 
102
- <h2>Files Overview</h2>
103
- <table>
104
- <thead><tr><th></th><th>File</th><th>Status</th><th>Language</th><th>Changes</th></tr></thead>
105
- <tbody>${filesTable}</tbody>
106
- </table>
233
+ ${risksHtml
234
+ ? `<h2>Things to watch</h2>\n${risksHtml}`
235
+ : `<h2>Things to watch</h2>\n<p class="none-msg">No concerns identified.</p>`}
107
236
 
108
- <h2>File Details</h2>
109
- ${fileDetails}
237
+ <h2>Changed files</h2>
238
+ ${fileCards}
110
239
 
111
- <div style="margin-top:32px;padding-top:12px;border-top:1px solid #e5e7eb;color:#9ca3af;font-size:11px;">
112
- Generated by intent-spec explain &middot; Tokens: ${explanation.tokenUsage.input} in / ${explanation.tokenUsage.output} out
240
+ <div class="footer">
241
+ Generated by diffintel &middot; ${explanation.tokenUsage.input + explanation.tokenUsage.output} tokens used
113
242
  </div>
114
243
  </body>
115
244
  </html>`;
@@ -1 +1 @@
1
- {"version":3,"file":"html-report.js","sourceRoot":"","sources":["../../src/explain/html-report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"html-report.js","sourceRoot":"","sources":["../../src/explain/html-report.ts"],"names":[],"mappings":"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"}
@@ -5,15 +5,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.explainChanges = explainChanges;
7
7
  const sdk_1 = __importDefault(require("@anthropic-ai/sdk"));
8
- const SYSTEM_PROMPT = `You analyze code changes. Respond ONLY with valid JSON. Be extremely concise.
8
+ const SYSTEM_PROMPT = `You explain code changes for both developers and non-developers. Respond ONLY with valid JSON. Be concise but clear.
9
9
 
10
- IMPORTANT context rules for risk assessment:
11
- - You are given the BASE STATE (declarations before this diff) and RECENT GIT HISTORY (what happened to each file recently).
12
- - Use history to understand INTENT: if a recent commit removed something and this diff adds it back, that is a FIX/RESTORATION, not a breaking change.
13
- - RESTORATION: re-adding something that was recently removed is safe do NOT flag as high risk.
14
- - NEW addition: only flag as breaking if it introduces behavior that never existed before.
15
- - REMOVAL: flag as risky if it removes established functionality.
16
- - When history shows a recent problematic change, frame this diff as fixing/reverting that change.`;
10
+ Context rules:
11
+ - You are given BASE STATE, RECENT GIT HISTORY (with diffs), and the current changes.
12
+ - Use history to understand INTENT: if a recent commit broke something and this diff fixes it, categorize it as a FIX.
13
+ - Clearly separate what was FIXED from what are genuine RISKS.
14
+ - Write the description in plain language that a non-developer can understand.
15
+ - For file explanations, describe what each file does and what changed in simple terms.`;
17
16
  const ACTION_ICON = {
18
17
  added: "+",
19
18
  removed: "-",
@@ -26,7 +25,14 @@ async function explainChanges(files, rawDiff) {
26
25
  const entries = f.recentHistory
27
26
  .map((h) => ` - ${h.hash} ${h.message} (${h.age})`)
28
27
  .join("\n");
29
- return `- ${f.path}:\n${entries}`;
28
+ const latestDiff = f.recentHistory[0]?.diff;
29
+ const trimmedDiff = latestDiff && latestDiff.length > 1500
30
+ ? latestDiff.slice(0, 1500) + "\n... (truncated)"
31
+ : latestDiff;
32
+ const diffSection = trimmedDiff
33
+ ? `\n Most recent commit diff:\n${trimmedDiff.split("\n").map((l) => ` ${l}`).join("\n")}`
34
+ : "";
35
+ return `- ${f.path}:\n${entries}${diffSection}`;
30
36
  })
31
37
  .join("\n");
32
38
  const baseSummary = files
@@ -42,7 +48,7 @@ async function explainChanges(files, rawDiff) {
42
48
  return `- ${f.path} (${f.status}): ${changes}`;
43
49
  })
44
50
  .join("\n");
45
- // Truncate diff to ~4000 chars, prioritizing modified files
51
+ const fileList = files.map((f) => `- ${f.path} (${f.status})`).join("\n");
46
52
  const truncatedDiff = truncateDiff(rawDiff, 4000);
47
53
  const prompt = `## Recent git history for changed files
48
54
  ${historySummary || "(no prior history)"}
@@ -53,17 +59,29 @@ ${baseSummary || "(new files only, no prior state)"}
53
59
  ## Structural changes (this diff)
54
60
  ${structuralSummary || "(no structural changes detected)"}
55
61
 
62
+ ## Files changed
63
+ ${fileList}
64
+
56
65
  ## Diff (truncated)
57
66
  ${truncatedDiff || "(empty diff)"}
58
67
 
59
68
  Respond with JSON:
60
- { "title": "<60 char PR title>",
61
- "description": "<2-4 sentences summarizing the changes>",
62
- "risks": [{"level":"low|medium|high","description":"<one sentence>"}] }`;
69
+ {
70
+ "title": "<60 char title for these changes>",
71
+ "description": "<2-4 sentences in plain language explaining what changed and why, suitable for non-developers>",
72
+ "fixes": [{"description": "<what was fixed or restored, one sentence>"}],
73
+ "risks": [{"level": "low|medium|high", "description": "<genuine new risk, one sentence>"}],
74
+ "fileExplanations": [{"path": "<file path>", "summary": "<1-2 sentences explaining what this file does and what changed>", "notes": ["<thing to consider about this specific change>"]}]
75
+ }
76
+
77
+ Rules:
78
+ - "fixes": things this change REPAIRS or RESTORES (e.g., re-adding security that was removed). Can be empty.
79
+ - "risks": only GENUINE new concerns, NOT things being fixed. If a change restores previous behavior, that is a fix, not a risk. Can be empty.
80
+ - "fileExplanations": one entry per changed file, plain language. "notes" are file-specific things to consider — edge cases, testing suggestions, behavioral changes. Can be empty array if nothing notable.`;
63
81
  const client = new sdk_1.default();
64
82
  const message = await client.messages.create({
65
83
  model: "claude-sonnet-4-5-20250929",
66
- max_tokens: 512,
84
+ max_tokens: 1024,
67
85
  system: SYSTEM_PROMPT,
68
86
  messages: [{ role: "user", content: prompt }],
69
87
  });
@@ -81,24 +99,28 @@ Respond with JSON:
81
99
  parsed = JSON.parse(cleaned);
82
100
  }
83
101
  catch {
84
- // Fallback if LLM doesn't return valid JSON
85
102
  parsed = {
86
103
  title: "Code changes",
87
104
  description: text.slice(0, 200),
105
+ fixes: [],
88
106
  risks: [{ level: "low", description: "LLM response was not valid JSON; showing raw text." }],
107
+ fileExplanations: [],
89
108
  };
90
109
  }
91
110
  return {
92
111
  title: parsed.title || "Code changes",
93
112
  description: parsed.description || "",
113
+ fixes: Array.isArray(parsed.fixes) ? parsed.fixes : [],
94
114
  risks: Array.isArray(parsed.risks) ? parsed.risks : [],
115
+ fileExplanations: Array.isArray(parsed.fileExplanations)
116
+ ? parsed.fileExplanations.map((fe) => ({ ...fe, notes: Array.isArray(fe.notes) ? fe.notes : [] }))
117
+ : [],
95
118
  tokenUsage,
96
119
  };
97
120
  }
98
121
  function truncateDiff(diff, maxLen) {
99
122
  if (diff.length <= maxLen)
100
123
  return diff;
101
- // Split by file sections, keep as many as fit
102
124
  const sections = diff.split(/^diff --git /m).filter(Boolean);
103
125
  let result = "";
104
126
  for (const section of sections) {
@@ -1 +1 @@
1
- {"version":3,"file":"llm-explain.js","sourceRoot":"","sources":["../../src/explain/llm-explain.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"llm-explain.js","sourceRoot":"","sources":["../../src/explain/llm-explain.ts"],"names":[],"mappings":"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"}
@@ -3,6 +3,7 @@ export interface FileHistoryEntry {
3
3
  hash: string;
4
4
  message: string;
5
5
  age: string;
6
+ diff?: string;
6
7
  }
7
8
  export interface FileDiff {
8
9
  path: string;
@@ -34,14 +35,24 @@ export interface FileAnalysis {
34
35
  recentHistory: FileHistoryEntry[];
35
36
  rawDiff: string;
36
37
  }
38
+ export interface Fix {
39
+ description: string;
40
+ }
37
41
  export interface Risk {
38
42
  level: "low" | "medium" | "high";
39
43
  description: string;
40
44
  }
45
+ export interface FileExplanation {
46
+ path: string;
47
+ summary: string;
48
+ notes: string[];
49
+ }
41
50
  export interface LLMExplanation {
42
51
  title: string;
43
52
  description: string;
53
+ fixes: Fix[];
44
54
  risks: Risk[];
55
+ fileExplanations: FileExplanation[];
45
56
  tokenUsage: {
46
57
  input: number;
47
58
  output: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diffintel",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "description": "AI-powered structural diff explainer for pull requests",
5
5
  "bin": {
6
6
  "diffintel": "dist/cli.js"