heyiam 0.2.26 → 0.2.27

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/dist/export.js CHANGED
@@ -90,14 +90,14 @@ function writeAndTrack(filePath, content, files) {
90
90
  return statSync(filePath).size;
91
91
  }
92
92
  // ── Markdown Export ────────────────────────────────────────────
93
- export async function exportMarkdown(dirName, cache, sessions, outputPath) {
93
+ export async function exportMarkdown(dirName, cache, sessions, outputPath, opts) {
94
94
  const files = [];
95
95
  let totalBytes = 0;
96
96
  mkdirSync(outputPath, { recursive: true });
97
97
  const { result } = cache;
98
98
  const title = cache.title ?? displayNameFromDir(dirName);
99
99
  // README.md — project narrative
100
- const readme = buildReadme(title, result, sessions);
100
+ const readme = buildReadme(title, result, sessions, opts?.totalFilesChanged);
101
101
  totalBytes += writeAndTrack(join(outputPath, 'README.md'), readme, files);
102
102
  // sessions/*.md — per-session breakdowns
103
103
  const sessionsDir = join(outputPath, 'sessions');
@@ -113,7 +113,7 @@ export async function exportMarkdown(dirName, cache, sessions, outputPath) {
113
113
  totalBytes += writeAndTrack(join(outputPath, 'project.json'), projectJson, files);
114
114
  return { files, totalBytes, outputPath };
115
115
  }
116
- function buildReadme(title, result, sessions) {
116
+ function buildReadme(title, result, sessions, totalFilesChanged) {
117
117
  const lines = [];
118
118
  lines.push(`# ${title}\n`);
119
119
  lines.push(result.narrative);
@@ -146,7 +146,7 @@ function buildReadme(title, result, sessions) {
146
146
  lines.push(`- Sessions: ${sessions.length}`);
147
147
  const totalLoc = sessions.reduce((sum, s) => sum + s.linesOfCode, 0);
148
148
  const totalMin = computeMergedSessionDuration(sessions);
149
- const totalFiles = sessions.reduce((sum, s) => sum + s.filesChanged.length, 0);
149
+ const totalFiles = totalFilesChanged ?? new Set(sessions.flatMap(s => s.filesChanged.map(f => f.path))).size;
150
150
  lines.push(`- Lines of code: ${totalLoc.toLocaleString()}`);
151
151
  lines.push(`- Total time: ${(totalMin / 60).toFixed(1)}h`);
152
152
  lines.push(`- Files changed: ${totalFiles}`);
@@ -223,7 +223,7 @@ export async function exportHtml(dirName, cache, sessions, outputPath, username
223
223
  // Compute stats the same way the dashboard does
224
224
  const totalLoc = sessions.reduce((sum, s) => sum + s.linesOfCode, 0);
225
225
  const totalDurationMinutes = computeMergedSessionDuration(sessions);
226
- const totalFilesChanged = opts?.totalFilesChanged ?? sessions.reduce((sum, s) => sum + s.filesChanged.length, 0);
226
+ const totalFilesChanged = opts?.totalFilesChanged ?? new Set(sessions.flatMap(s => s.filesChanged.map(f => f.path))).size;
227
227
  // Agent duration: sum child durations across all orchestrated sessions
228
228
  const totalAgentMinutes = sessions
229
229
  .filter((s) => s.isOrchestrated && s.children)
@@ -317,7 +317,7 @@ function buildProjectRenderInputs(dirName, cache, sessions, username, opts) {
317
317
  }));
318
318
  const totalLoc = sessions.reduce((sum, s) => sum + s.linesOfCode, 0);
319
319
  const totalDurationMinutes = computeMergedSessionDuration(sessions);
320
- const totalFilesChanged = opts?.totalFilesChanged ?? sessions.reduce((sum, s) => sum + s.filesChanged.length, 0);
320
+ const totalFilesChanged = opts?.totalFilesChanged ?? new Set(sessions.flatMap(s => s.filesChanged.map(f => f.path))).size;
321
321
  const totalAgentMinutes = sessions
322
322
  .filter((s) => s.isOrchestrated && s.children)
323
323
  .reduce((sum, s) => sum + s.children.reduce((cs, c) => cs + c.durationMinutes, 0), 0);
@@ -427,7 +427,7 @@ export function createRouteContext(sessionsBasePath, dbPath) {
427
427
  const parentMetas = proj.sessions.filter(s => !s.isSubagent);
428
428
  const allStats = await Promise.all(parentMetas.map((m) => getSessionStats(m, proj.name)));
429
429
  const totalLoc = allStats.reduce((s, st) => s + st.loc, 0);
430
- const totalFiles = allStats.reduce((s, st) => s + st.files, 0);
430
+ const totalFiles = db.prepare('SELECT COUNT(DISTINCT file_path) as c FROM session_files WHERE session_id IN (SELECT id FROM sessions WHERE project_dir = ?)').get(proj.dirName)?.c ?? allStats.reduce((s, st) => s + st.files, 0);
431
431
  const naiveDuration = allStats.reduce((s, st) => s + st.duration, 0);
432
432
  const totalDuration = computeMergedDurationFromDb(db, proj.dirName, naiveDuration);
433
433
  let totalAgentDuration = totalDuration;
@@ -71,8 +71,9 @@ export function createExportRouter(ctx) {
71
71
  return;
72
72
  }
73
73
  const cache = data.enhanceCache ?? buildFallbackCache(data.sessions);
74
+ const totalFilesChanged = data.project.totalFiles;
74
75
  const outputPath = path.join(EXPORTS_BASE, dirName, 'markdown');
75
- const result = await exportMarkdown(dirName, cache, data.sessions, outputPath);
76
+ const result = await exportMarkdown(dirName, cache, data.sessions, outputPath, { totalFilesChanged });
76
77
  res.json(result);
77
78
  }
78
79
  catch (err) {
@@ -90,8 +91,9 @@ export function createExportRouter(ctx) {
90
91
  return;
91
92
  }
92
93
  const cache = data.enhanceCache ?? buildFallbackCache(data.sessions);
94
+ const totalFilesChanged = data.project.totalFiles;
93
95
  const outDir = safeExportPath(outputPath, dirName, 'markdown');
94
- const result = await exportMarkdown(dirName, cache, data.sessions, outDir);
96
+ const result = await exportMarkdown(dirName, cache, data.sessions, outDir, { totalFilesChanged });
95
97
  res.json(result);
96
98
  }
97
99
  catch (err) {
@@ -153,9 +155,10 @@ export function createExportRouter(ctx) {
153
155
  return;
154
156
  }
155
157
  const cache = data.enhanceCache ?? buildFallbackCache(data.sessions);
158
+ const totalFilesChanged = data.project.totalFiles;
156
159
  // Re-use exportMarkdown to a temp dir, then zip the result
157
160
  const tmpDir = path.join(EXPORTS_BASE, '.tmp', `${dirName}-${Date.now()}`);
158
- const result = await exportMarkdown(dirName, cache, data.sessions, tmpDir);
161
+ const result = await exportMarkdown(dirName, cache, data.sessions, tmpDir, { totalFilesChanged });
159
162
  // Read files into memory and zip
160
163
  const entries = result.files.map((filePath) => ({
161
164
  path: path.relative(tmpDir, filePath),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "heyiam",
3
- "version": "0.2.26",
3
+ "version": "0.2.27",
4
4
  "description": "Turn AI coding sessions into portfolio case studies",
5
5
  "type": "module",
6
6
  "license": "MIT",