this repo has no description
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Fix ESLint issues in CLI

- Add explicit null/undefined checks
- Filter null values from project name arrays
- Use String() for template literal number interpolation
- Remove unnecessary async from synchronous functions
- Add proper error type handling in catch blocks
- Add DailySummaryParsed interface to replace any

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>

alice f5ee12a3 f704e570

+61 -47
+23 -17
src/cli/index.ts
··· 5 5 import { getStats, getDatesWithoutBragSummary, getSessionsForDate, saveDailySummary } from '../core/db'; 6 6 import { generateDailyBragSummary } from '../core/summarizer'; 7 7 8 + interface DailySummaryParsed { 9 + projects: { name: string; summary: string }[]; 10 + } 11 + 8 12 const { values, positionals } = parseArgs({ 9 13 args: Bun.argv.slice(2), 10 14 options: { ··· 20 24 const command = positionals[0]; 21 25 22 26 async function main() { 23 - if (values.help || !command) { 27 + if (values.help === true || !command) { 24 28 printHelp(); 25 29 return; 26 30 } ··· 36 40 break; 37 41 38 42 case 'status': 39 - await statusCommand(); 43 + statusCommand(); 40 44 break; 41 45 42 46 case 'serve': ··· 86 90 `); 87 91 } 88 92 89 - async function statusCommand() { 93 + function statusCommand() { 90 94 const sessionStats = getSessionStats(); 91 95 const dbStats = getStats(); 92 96 93 97 console.log('\n📊 Worklog Status\n'); 94 98 console.log('Session Files:'); 95 - console.log(` Total files: ${sessionStats.totalFiles}`); 96 - console.log(` Projects: ${sessionStats.totalProjects}`); 99 + console.log(` Total files: ${String(sessionStats.totalFiles)}`); 100 + console.log(` Projects: ${String(sessionStats.totalProjects)}`); 97 101 console.log(` Claude paths: ${sessionStats.claudePaths.join(', ')}`); 98 102 console.log('\nProcessed Data:'); 99 - console.log(` Sessions summarized: ${dbStats.totalSessions}`); 100 - console.log(` Days with work: ${dbStats.totalDays}`); 101 - console.log(` Projects tracked: ${dbStats.totalProjects}`); 103 + console.log(` Sessions summarized: ${String(dbStats.totalSessions)}`); 104 + console.log(` Days with work: ${String(dbStats.totalDays)}`); 105 + console.log(` Projects tracked: ${String(dbStats.totalProjects)}`); 102 106 console.log(''); 103 107 } 104 108 105 109 async function serveCommand() { 106 110 // Dynamic import to avoid loading web server code unless needed 107 111 const { startServer } = await import('../web/server'); 108 - await startServer(); 112 + startServer(); 109 113 } 110 114 111 115 async function regenerateCommand(force: boolean) { ··· 126 130 return; 127 131 } 128 132 129 - console.log(`\n📝 Regenerating ${dates.length} daily summaries...\n`); 133 + console.log(`\n📝 Regenerating ${String(dates.length)} daily summaries...\n`); 130 134 131 135 for (const date of dates) { 132 136 const sessions = getSessionsForDate(date); ··· 134 138 135 139 try { 136 140 const summary = await generateDailyBragSummary(date, sessions); 137 - const projectNames = [...new Set(sessions.map(s => s.project_name))]; 141 + const projectNames = [...new Set(sessions.map(s => s.project_name))].filter((n): n is string => n !== null); 138 142 saveDailySummary(date, summary, projectNames, sessions.length); 139 143 140 144 // Parse and show preview 141 - const parsed = JSON.parse(summary); 142 - const preview = parsed.projects.map((p: any) => p.name).join(', '); 145 + const parsed = JSON.parse(summary) as DailySummaryParsed; 146 + const preview = parsed.projects.map((p) => p.name).join(', '); 143 147 console.log(` ✓ ${date}: ${preview}`); 144 - } catch (error) { 145 - console.error(` ✗ ${date}: ${error}`); 148 + } catch (error: unknown) { 149 + const errorMessage = error instanceof Error ? error.message : String(error); 150 + console.error(` ✗ ${date}: ${errorMessage}`); 146 151 } 147 152 } 148 153 149 154 console.log('\n✅ Done!\n'); 150 155 } 151 156 152 - main().catch((error) => { 153 - console.error('Error:', error); 157 + main().catch((error: unknown) => { 158 + const errorMessage = error instanceof Error ? error.message : String(error); 159 + console.error('Error:', errorMessage); 154 160 process.exit(1); 155 161 });
+38 -30
src/cli/process.ts
··· 87 87 // Build date filter 88 88 let dateFilter: { type: 'date'; value: string } | { type: 'range'; start: string; end: string } | null = null; 89 89 90 - if (date) { 90 + if (date !== undefined) { 91 91 const targetDate = parseDate(date); 92 92 dateFilter = { type: 'date', value: targetDate }; 93 93 console.log(`\n📅 Filtering to date: ${targetDate}\n`); 94 - } else if (week) { 94 + } else if (week !== undefined) { 95 95 const { start, end } = parseWeek(week); 96 96 dateFilter = { type: 'range', start, end }; 97 97 console.log(`\n📅 Filtering to week: ${start} to ${end}\n`); ··· 103 103 104 104 // Pre-filter by file modification time if date filter is set 105 105 // This avoids parsing thousands of files just to check their dates 106 - if (dateFilter && sessions.length > 0) { 106 + if (dateFilter !== null && sessions.length > 0) { 107 107 const originalCount = sessions.length; 108 108 const bufferDays = 2; // Allow some buffer for timezone/edge cases 109 109 ··· 124 124 s.modifiedAt >= startDate && s.modifiedAt <= endDate 125 125 ); 126 126 127 - console.log(`Pre-filtered ${originalCount} → ${sessions.length} sessions by modification time\n`); 127 + console.log(`Pre-filtered ${String(originalCount)} → ${String(sessions.length)} sessions by modification time\n`); 128 128 } 129 129 130 130 if (sessions.length === 0) { ··· 132 132 return { sessionsProcessed: 0, errors: 0 }; 133 133 } 134 134 135 - console.log(`Found ${sessions.length} session(s) to check\n`); 135 + console.log(`Found ${String(sessions.length)} session(s) to check\n`); 136 136 137 137 // Process sessions in parallel with concurrency limit 138 138 const CONCURRENCY = 10; 139 - const results: Array<{ 139 + const results: { 140 140 session: SessionFile; 141 141 result?: Awaited<ReturnType<typeof processSession>>; 142 142 error?: unknown; 143 - }> = []; 143 + }[] = []; 144 144 145 145 // Process in batches 146 146 for (let i = 0; i < sessions.length; i += CONCURRENCY) { ··· 165 165 const datesProcessed = new Set<string>(); 166 166 167 167 for (const [projectName, projectSessions] of Object.entries(byProject)) { 168 - console.log(`📁 ${projectName} (${projectSessions.length} sessions)`); 168 + console.log(`📁 ${projectName} (${String(projectSessions.length)} sessions)`); 169 169 170 170 let skipped = 0; 171 171 let filtered = 0; 172 172 173 173 for (const session of projectSessions) { 174 174 const resultEntry = results.find((r) => r.session === session); 175 - if (!resultEntry) continue; 175 + if (resultEntry === undefined) continue; 176 176 177 - if (resultEntry.error) { 177 + if (resultEntry.error !== undefined) { 178 178 errors++; 179 - console.log(` ✗ ${session.sessionId.slice(0, 8)}... - Error: ${resultEntry.error}`); 179 + let errorMessage: string; 180 + if (resultEntry.error instanceof Error) { 181 + errorMessage = resultEntry.error.message; 182 + } else if (typeof resultEntry.error === 'object' && resultEntry.error !== null) { 183 + errorMessage = JSON.stringify(resultEntry.error); 184 + } else if (typeof resultEntry.error === 'string') { 185 + errorMessage = resultEntry.error; 186 + } else { 187 + errorMessage = 'Unknown error'; 188 + } 189 + console.log(` ✗ ${session.sessionId.slice(0, 8)}... - Error: ${errorMessage}`); 180 190 if (verbose) { 181 191 console.error(resultEntry.error); 182 192 } 183 193 continue; 184 194 } 185 195 186 - const result = resultEntry.result!; 196 + const result = resultEntry.result; 197 + if (result === undefined) continue; 187 198 188 199 if (result.filtered) { 189 200 filtered++; ··· 198 209 continue; 199 210 } 200 211 201 - if (result.date) { 202 - datesProcessed.add(result.date); 203 - } 212 + datesProcessed.add(result.date); 204 213 processed++; 205 214 206 215 const duration = formatDuration(result.startTime, result.endTime); ··· 208 217 console.log(` ✓ ${session.sessionId.slice(0, 8)}... (${duration}) → "${summary}..."`); 209 218 } 210 219 211 - const notes = []; 212 - if (skipped > 0) notes.push(`${skipped} empty`); 213 - if (filtered > 0) notes.push(`${filtered} outside date range`); 220 + const notes: string[] = []; 221 + if (skipped > 0) notes.push(`${String(skipped)} empty`); 222 + if (filtered > 0) notes.push(`${String(filtered)} outside date range`); 214 223 if (notes.length > 0) { 215 224 console.log(` (${notes.join(', ')} skipped)`); 216 225 } ··· 221 230 console.log('📝 Generating daily summaries...\n'); 222 231 await regenerateSummariesForDates(datesProcessed, verbose); 223 232 224 - console.log(`\n✅ Done! Processed ${processed} sessions (${errors} errors)\n`); 233 + console.log(`\n✅ Done! Processed ${String(processed)} sessions (${String(errors)} errors)\n`); 225 234 console.log('Run `bun cli serve` to view your worklog.\n'); 226 235 227 236 return { sessionsProcessed: processed, errors }; ··· 255 264 ); 256 265 257 266 if (verbose) { 258 - console.log(` Parsed: ${parsed.messages.length} messages, ${Object.keys(parsed.stats.toolCalls).length} tool types`); 267 + console.log(` Parsed: ${String(parsed.messages.length)} messages, ${String(Object.keys(parsed.stats.toolCalls).length)} tool types`); 259 268 } 260 269 261 270 // Check date filter BEFORE expensive LLM summarization ··· 304 313 305 314 if (verbose) { 306 315 console.log(` Summary: ${summary.shortSummary}`); 307 - console.log(` Accomplishments: ${summary.accomplishments.length}`); 316 + console.log(` Accomplishments: ${String(summary.accomplishments.length)}`); 308 317 } 309 318 310 319 // Filter out sessions that the LLM determined had no real work ··· 364 373 ); 365 374 366 375 if (verbose) { 367 - console.log(` Generating brag summary for ${date} (${sessions.length} sessions)`); 376 + console.log(` Generating brag summary for ${date} (${String(sessions.length)} sessions)`); 368 377 if (newProjectNames.size > 0) { 369 378 console.log(` New projects: ${[...newProjectNames].join(', ')}`); 370 379 } 371 380 } 372 381 373 - const bragSummary = await generateDailyBragSummary(date, sessions, newProjectNames); 374 - const projectNames = [...new Set(sessions.map((s) => s.project_name))]; 382 + const filteredNewProjects = new Set([...newProjectNames].filter((n): n is string => n !== null)); 383 + const bragSummary = await generateDailyBragSummary(date, sessions, filteredNewProjects); 384 + const projectNames = [...new Set(sessions.map((s) => s.project_name))].filter((n): n is string => n !== null); 375 385 376 386 saveDailySummary(date, bragSummary, projectNames, sessions.length); 377 387 ··· 389 399 390 400 for (const session of sessions) { 391 401 const key = session.projectName; 392 - if (!grouped[key]) { 393 - grouped[key] = []; 394 - } 402 + grouped[key] ??= []; 395 403 grouped[key].push(session); 396 404 } 397 405 ··· 399 407 } 400 408 401 409 function formatDuration(start: string, end: string): string { 402 - if (!start || !end) return '?'; 410 + if (start === '' || end === '') return '?'; 403 411 404 412 const startDate = new Date(start); 405 413 const endDate = new Date(end); 406 414 const diffMs = endDate.getTime() - startDate.getTime(); 407 415 408 416 const minutes = Math.floor(diffMs / 60000); 409 - if (minutes < 60) return `${minutes}m`; 417 + if (minutes < 60) return `${String(minutes)}m`; 410 418 411 419 const hours = Math.floor(minutes / 60); 412 420 const remainingMinutes = minutes % 60; 413 - return `${hours}h${remainingMinutes}m`; 421 + return `${String(hours)}h${String(remainingMinutes)}m`; 414 422 }